This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-02-09
Channels
- # announcements (20)
- # beginners (115)
- # calva (2)
- # clj-kondo (1)
- # clojure (48)
- # clojure-uk (21)
- # clojurescript (20)
- # css (1)
- # cursive (3)
- # datascript (11)
- # datomic (6)
- # duct (26)
- # emacs (5)
- # funcool (6)
- # off-topic (45)
- # perun (1)
- # precept (4)
- # quil (2)
- # re-frame (1)
- # shadow-cljs (251)
- # tools-deps (27)
- # uncomplicate (9)
I recall some ANSI-colored string screwing my emacs repl in the past (I would see escape codes instead of something legible), however now I'm using something that ansi-colors output and it looks fine. That makes me wonder if is there a 'good' and 'bad' way to color strings? For a tool of my own I wouldn't want to emit output that can look broken for certain users
That's why most tooling that does output coloring has an option to turn it off I guess.
Maybe CIDER was updated to allow ANSI-colored output since you had that problem?
I couldn't tell :) mix of blurry memories and custom emacs-isms But yes, an option can be the simplest approach
I believe that most programs like ls and friends check if output is a pipe or std-out and if the former, turns off coloring. I might be dreaming, though
Jansi has a way to probe the environment for ansi support, although it does not detect cider as such an environment.
@slipset Yes, that's exactly how it works. Otherwise it would be way too inconvenient turning colors on and off with command line args. The way coloring works is by emplacing color codes in the output string itself. The next program down the line removes this color information and draws those parts with the appropriate color.
Good afternoon/evening/morning?
I want to follow the book Clojure for Machine Learning (https://www.amazon.com/dp/1783284358/ref=cm_sw_r_cp_ep_dp_CJbkAbX33TGVE)
In Chapter 1 about linear algebra (matrices), the clatrix library is used motivated by better performance but that library allows mutable matrices, defined by using def
.
I wonder whether there are some general guidelines for programming in Clojure, when working with mutable models?
I guess the question applies to the functional programming paradigm in general?
AFAICT, the general paradigm is "don't work with mutable data structures unless you really have to". E.g. when the performance is really important.
OK - let's imagine it is 😉
(I think most image libraries do not copy entire images all the time - to provide another example)
For example, even Pandas and Numpy offer their functions in two ways - one that mutates the data in-pace, and the other that creates a changed version of the data. Well, then you have to find the bottlenecks and restrict mutable data structure usage to those particular places. Everything else - immutable.
Worth pointing out that clojure.core has quite a wealth of array-related functions: from basic stuff to amap, areduce... Within reason, one can try preserving clojure's model even when working with mutable things. I wonder if transducers work with arrays? Can't immediately tell myself.
OK - but I was thinking whether there are any patterns for programming within those bottleneck areas
But it also depends on what you're doing I guess. If all you want to do is apply some linear non-concurrent pipeline where you don't share any data at all, then immutable data structures don't give you that much and you should be fine with something mutable.
Good point - I am also having an intuition about somethin strictly sequential
The only pattern I've seen is the one I have already described. Extract and confine all mutations under some API that doesn't mutate anything by itself. Similar to how transients are used in Clojure.
Thank you 🙂
So, in deftype
I can have primitive fields, or mutable fields, but not both (primitive mutable fields)?
I'm getting an impressively cryptic error:
#error {
:cause Bad type on operand stack
Exception Details:
Location:
dtype/VM.run()Ljava/lang/Object; @9: putfield
Reason:
Type long_2nd (current frame, stack[2]) is not assignable to integer
I do not know what you have tried, but Clojure/Java allows deftype
with mutable primitive fields. Here is an example from the core.rrb-vector contrib library: https://github.com/clojure/core.rrb-vector/blob/master/src/main/clojure/clojure/core/rrb_vector/rrbt.clj#L79-L80
yes, it's java Clojure; it seems to happen to some of the primitives, int
and byte
cause that, long
doesn't
I do not know what the difference between your use and core.rrb-vector's might be, but core.rrb-vector's use does not cause such an error.
float
causes that, double
doesn't. Apparently it has to do with the bitsize of the type. Short types get the shorted, huh
and has a couple of mutable int
fields
Still looks like a bug to me (at the bare minimum, the error message could be less arcane), but yeah, I can work with that
You can file an issue on http://ask.clojure.org if you consider it a bug, and see what the maintainers think. Precise reproducible code, version of Clojure used, error message, all useful in a report.
isn't the issue that Clojure uses longs and doubles? but you can't assign longs to ints and doubles to floats because of the possible loss of data.
you can assign 1 to e.g. int array location or pass it to an int-typed loop var just fine
After looking into this, I think the issue is that the other examples such as assigining to an array and whatnot, are methods that are subject to the Reflector which massages values to be what they need to be. But, set! is a special form that just spits out bytecode without trying to make things fit. so all it sees is that you're trying to emit bytecode that puts a long into an int field.
I am not sure exactly where the source of that error is -- perhaps the asm library that the Clojure compiler uses to generate Java byte code? If so, it is at a fairly low level that the issue is being caught and reported right now.
It is also for a fairly low level use case within Clojure that a lot of people don't ever reach for. Not everyone uses deftype, and among those who do, only some use mutable fields, and only some use fields with Java primitive types.
I agree that all other things being equal, it would be nice to have descriptive clear error messages that you can understand quickly the first time you see them. The cost of implementing such a clear error message for this kind of code may be fairly high relative to the number of people who would see it.
I guess one thing to clarify: that error is given by Java. Clojure happily writes the Class file for the type with the mismatched types.
so I guess it would be up to the bytecode emitter for set! to maybe do some checking.
Played a bit with this, out of curiosity. The following fails to compile:
(deftype A [^:unsynchronized-mutable ^long x]
P
(some-method [_]
(set! x (int 2))
(println x)))
...Because the type hint says long, but the method call says int. i.e. watch out for such inconsistencies.
Anyway what does your code look like?(defprotocol IVirtualMachine (run [code]))
(deftype VM [^int ^:unsynchronized-mutable pc]
IVirtualMachine
(run [code]
(set! pc 1))
)
1
is a Long in . You can check it with
(class 1)
Assigning longs to an int "slot" is inherently dangerous, since a long can always represent a bigger value than it is representable as an int
So it's a good thing that you need an explicit (set! pc (int 1))
It's inconsistent (you can assign 1 to an int array location or pass it to a int-typed loop var without any issues whatsoever)
deftype
aims to emit efficient code, so it wouldn't surprise me if it imposed greater constraints than those encountered in most other parts of the Clojure language
unchecked-add-int
, clojure.core/+
etc aren't extremely performance-oriented (AIUI: they balance performance with 'forgiveness'), which is the reason people may feel compelled to author e.g. https://github.com/ztellman/primitive-math for having more deterministic performance expectations
Here's another useless piece of micro-optimization trivia: https://gist.github.com/jsn/cfbf2e51393c4cba062898e452f0d23c ; trampoline
seems very fast until it's used for more than one function, and then it gets very slow.