This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-05-07
Channels
- # announcements (11)
- # architecture (2)
- # babashka (84)
- # beginners (226)
- # calva (7)
- # chlorine-clover (4)
- # cider (29)
- # clara (17)
- # clj-kondo (23)
- # cljs-dev (58)
- # cljsrn (60)
- # clojure (172)
- # clojure-europe (24)
- # clojure-finland (2)
- # clojure-italy (6)
- # clojure-nl (8)
- # clojure-spec (4)
- # clojure-uk (22)
- # clojurescript (44)
- # conjure (39)
- # core-async (64)
- # cursive (76)
- # data-science (15)
- # duct (3)
- # emacs (2)
- # events (5)
- # fulcro (30)
- # helix (4)
- # jackdaw (5)
- # juxt (1)
- # kaocha (1)
- # leiningen (4)
- # off-topic (9)
- # pathom (22)
- # re-frame (9)
- # reagent (33)
- # reitit (3)
- # ring (10)
- # ring-swagger (2)
- # shadow-cljs (192)
- # spacemacs (27)
- # specter (2)
- # sql (59)
- # vim (2)
When I declare an atom variable in clojure, why do I have to deref it to get just the value? If I don't deref it, I can still see the value, but in like a more complex and verbose structure
BUt also when I'm using it inside the 'swap!' function, I don't deref it...so I'm not sure why is that
swap! is a function, that takes a place, and puts a new content in it
so you need to pass a "place" for it to make sense
@foo generally (not just for atoms) takes a thing that can have a value and gets the value out of it
Atom is a data structure that holds the value "inside" them to control the consistency, concurrency, etc
atoms don't need to be "variables", they are first class data and it's easy to pass it / hold it etc. which is clumsier with variables
Swap! receives a function that will be executed inside the atom
it supplies a return value that replaces the content of the atom
it's doesn't lock or scope the atom per se
@sunchaesk for a more concrete example - when I do (def g (partial map f))
the var
f is captured, and I implicitly use the value not the container itself
this leads to weird behavior - if I change f later, I need to remember to change g
there's an "opposite" to @
, which is #'
, that lets me capture the var itself instead of the contents (def g (partial map #'f))
in fact, @#'foo
is the same as foo
if foo is a var
atoms are meant to be changed by application code at runtime, so it's easy to get the container, and an extra step to get what's inside - that's expected to happen as late as possible
vars are meant to be changed by a developer while working on one's code, so it's easy to get the contents, and an extra step to get the container
each one makes the "expected" use simpler
in fact, an atom is often in a var - though you can also use them first class as an arg to something that uses them / captures them
there's a great Rich Hickey talk about place oriented vs. value oriented programming
atom is explicitly meant to be a "place"
I thought it was supposed to represent an identity. the main difference being that places (on their own) don’t follow the epochal time model.
are java.util.HashMap or java.util.Date instances identities?
that’s a good point
i guess atom is really just supposed to be a reference type
with sane semantics
yeah - what I tried to get at was that its fundamental utility was to be a location, and the reason we prefer it over alternatives (which I didn't get into), is the sane behavior under concurrency
if I'm using identity or place here incorrectly I do want to know though
me too
I guess it is a place, but the fact that it’s bundled with a recipe for change and perception is important (which distinguishes it from many other places)
¯\(ツ)/¯
but that's opt in - if you use reset!
you get none of that safety, and only as much as you'd have with a var, or a thread safe mutable hash-map
thread safety is still important, but yea. I think I jumped the gun to say it wasn’t a place for some reason
my bad!
if you have a document describing what makes something an identify vs. place I'd be interested, I'm not totally sure when I'd use the term identity
(outside eg. what kind of equality I expect to be used)
the first thing I find in google is this https://clojure.org/about/state#_working_models_and_identity
Hum... I don't think an identity is the same as a place. Like a place is just what it says, a place where you put things and grab things from.
identities don’t have to be places eg.
(def people-by-id
{"1230u1203912" {:name "Bob"}
"129u9cnu1209u12" {:name "Bob"}})
here, you have two people, with different identities, but their identity isn’t tied to a place
Ya, exactly. An identity is just an identifier for something. The only place where there's a connection is that a thing that changes cannot be identified by its form, since its form changes over time
well, i think the identity is the logical connection of values over time
maybe it's sort of a trio: identity / place / value - your identities are value based, you can also have place based identities (standard object identity)
it’s nice to have a reification of that logical identity (an identifier)
well, any unique value can be used as an identifier
I nerd sniped myself into rewatching the value of values, it's a good talk
because places are unique. unfortunately, they can’t be copied which is annoying
I watched it earlier today during lunch
I don't really know if Clojure offers a better concept of identity for things that change form over time then a place?
you can use any* identifier that’s unique
like a guid
I mean, if you call =
on an atom, that's the only way to get true
- is if it points to the same place
Right, atoms don't carry a stable Id with them, so they are effectively identified by place no?
yes, but they’re not the only* option
well, the other reference types
vars, refs, and atoms
agents, volatiles
vars are usually looked at in terms of their owning structure and name
but yeah, the others are just identity based
but you can use a guid as an identifier in clojure
sure - not on the language level, but on the level of convention right?
and instead of getting its current value from memory (like atoms), you could get its current value from the disk or the network
I mean, without me creating my own. Are there any construct on Clojure who can model changing values whose identity is not based on a place?
they are usually looked up by the identity of their ns, (which is looked up by name) plus their name
though technically in bytecode they just get looked up by place, that's not the semantics we usually engage with
I also have no idea how refs work
since they use mvcc, I’m not sure whether that counts as having multiple places
I think it's more that mvcc coordinates the update of their contents, but the contents stay in one place
@U0K064KQV when I use vars, I am explicitly asking for an ns by symbol, and I am explciitly looking for one name in that ns by symbol, if that goes out of sync (eg. because clojure.tools.namespace/refresh recreated the ns out from under me), I will experience that as a bug in my code and fix it by redoing the original lookup by recompiling
we very rarely even check var equality, they implicitly deref
Right, but that's a place, albeit not a memory address, but it's the same thing, it's just an address in the namespace map
@U0K064KQV, i’m not sure what you’re getting at. logically, identifiers don’t have to be places. I’m not sure if identifiers are only implemented as places in “clojure” (does using java libs count? what’s wrong with using a library?).
The way I see it it's like:
{:a 10}
and {:a 10}
are the same thing because they have the same value. So no matter what place you put them in, they are the same thing
@U0K064KQV it's not a place, because it's looked up by tokens that we assign meanings to, not by location in memory
(in terms of program logic at least - of course in bytecode most of these things become places...)
and from a technical perspective, the jvm is allowed to move stuff around in memory. the OS is also allowed to move stuff around in memory without telling us too
But if you want to model something that changes like:
{:a 10}
and {:a 20}
now what? If you say these are both the :amount-of-money-in-my-bank-account
So one way is to agree on a place where we will put the amount of money in my bank account
And now we can say, whatever is in that place must be the :amount-of-money-in-my-bank-account
or to arrange ot look it up by a known identifier
in c we would be using places explicitly for everything but primitives, but we have other conventions in our language semantics that aren't place oriented
as far as my program is concerned clojure.core/+ is an identity, despite the fact that reloading clojure.core could change its place
you can use places for identity, but you don’t have to.
and that identity is based on the symbols I use to look it up
Ya I know, I'm just saying that one way to create an identity for something that changes. The other way is to put a tag on the thing
But if the tag is not on the thing, then in my view it is still then that the place is the identity
not all places are identities
places can be identifiers, but they don’t have to be
Let's take atom again. It is the place of the atom that tells me what the value inside it refers too
sounds good
atoms are an example of using a place as an identity
but there are are also examples of places that aren’t identities
I guess my point is, I don't think there are any standard construct in Clojure that are basically a stable Id + a mutable section
there’s enough stuff in clojure, that I can’t say for sure
but I think vars might be a counter example to taht
like when do (def foo 42)
I think it might create an actual new place
It depends what you want to model? Like 42 is 42 because of its value, not because it is found in foo
i’m not talking about 42, I’m talking my.namespace/foo
But if foo is something that changes value over time, and 42 is supposed to be a foo and not the value 42, then foo would be the identity as well no?
foo’s value is currently 42, but it might change to -42
the var it points to
I would say my.namespace/foo
’s identifier is my.namespace/foo
, not whatever its memory address is
> This means that, unless they have been unmap-ed, Var objects are stable references and need not be looked up every time. It also means that namespaces constitute a global environment in which, as described in Evaluation, the compiler attempts to resolve all free symbols as Vars.
also, outside of -128...127 for integral types, numbers are never places, only values
I guess you could consider an interned var to be a combination of a stable id, the symbol's namespace+name and the possibility changing value contained in the Var
I think that's my criteria for if identity is a place or not 😝. If you take the thing and move it somewhere else, can you still know what's its identity? If you can't, then the place was acting as the identity, and having lost the knowledge of where the thing was, so have you lost its identity. If you can, then the identity is within the thing itself, and not based on where it was.
given a var, you can find its symbol
=> (.sym #'+)
+
not only that - standard idiomatic language constructs find them by that name
Ya, but I honestly don't really see that as being different. If I said, ok, this function will always be at memory location xyz. Or, okay this function will always be at key xyz in namespace map
the difference is that one of those is the normal path for finding a var, and the other is a rare special case
It still feels like we're doing place oriented programming. Because now everything relies on this implicit agreement and knowledge of where things are going to be and what each thing at each place is supposed to represent
And if someone messes up, and doesn't put the right thing in the right place, everything breaks
i agree that vars are still place oriented. “any time new values overwrite old values, you’re doing PLOP”.
but hopefully, your whole program isn’t all about places
True, also I think places that are at least consistent throughout the whole execution are much less brittle and easier to deal with. And most idiomatic Clojure never changes the value of a Var after the first time it is defined
until you ask it to (ns-unmap) use a tool that does that for you (ns/refresh)
clojure has "two sets of rule" - for dev vs. runtime, and I think that's an important quality
one of those rules are a very strong convention and not rules per se, but luckily the conventions are strong enough
Going by Are We There Yet, a name for something that changes in atomic successions and is perceivable by others without stopping anyone is what I'd call an identity. And in order to make something (with computers) that represents an identity, then we need values. An identity is a label we (humans) give to a sequence of causally-related values. Which means values are the more primitive thing. Whereas with a mutable datastructure, all you have is a place, it's neither an identity (in the sense described above), nor a value.
from https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/SimpleMadeEasy.md, > Objects complect state, identity, and value. while we would like to represent identities using references that obey the epochal time model, objects can still be used to represent identities (although this is ill advised).
and just because you can use an atom to represent an identity. you could also misuse it to represent something besides an identity. so a construct that follows the epochal time model does not imply that the construct must represent an identity
wow, 8 years ago https://www.youtube.com/watch?v=-6BsiVyC1kM
@sunchaesk that talk is what brought me to clojure. It’s REALLY good
yeah I've heard others saying that this talk is great. I'll make sure to check it out
If you prefer reading to watching/listening, transcripts of many talks available here. Also good for searching for key words later if you want to find something you remember only one word or two of: https://github.com/matthiasn/talk-transcripts
Thxs for the transcript @andy.fingerhut
I also had a question about functional programming while watching the talk by Rich Hickey Value of Values He said that one thing people are pleased about is that you can share the values freely without having to worry I get the part that talks about how you don't have to worry because the value is immutable, but I don't understand why it is only functional programming that allows you to share data freely and not same between OOP and FP
Do you mean why does OOP not use immutables, or what is it about OOP that makes sharing hard compared to FP, or something else
(this is a tangent I'm about to get on, not an answer to your question) Personally, I don't think mutability vs immutability should be baked into the definition of OOP -- it mostly is, but to me its mutable as a historical detail, not because it has to be. To me, a language with data and functions tightly bundled, and all the other aspects of OOP, but where each function returned a new, updated object, instead of updating some living piece of memory somewhere, would still be OOP -- it is the object that's important (and fortunately I could maybe even argue that in any flame war this sparks, since its right in the name). But of course, then we're just talking about language, instead of the ideas behind them, and what ideas the language should refer to -- and when people say OOP, they are referring to programming built on mutation. And why wouldn't they? I know of no real immutable OOP, although I've done a lot of experimentation there myself
Anyways, in my personal language, imperative programming is what I call a language that expresses its change as side effects, and declarative programming one that expresses it as a fresh return value of some data (thereby having the data only represent, or describe, what will become a change), and they're a much lower level property than being, say, 'OOP'
@zdot101 I'd suggest that even in Clojure (or more extreme, even in scheme or forth) functions and data are tightly coupled - it's just that strategically, less work is put into proliferating data types and more into proliferating the number of functions on the small set of data types
Ah, but I said tightly bundled . Granted, I'm trying to think now of a more rigorous definition to differentiate the two, but I think the main difference is I was referring to was not their coupling (although bundling itself couples), but to the fact that they are an atomic unit; when you deal with objects, you don't get them separate. Of course, as you dig into that, it gets trickier -- being 'together' has less meaning as you zoom in and get more rigorous, and a more fitting way of explaining that sort of thing is that they are still individual things, but with a different set of relationships drawn between them than, say, functions and data in Clojure.
I think there’s a fair argument to be made that Erlang is an example of an immutable OOP.
This is really interesting. It annoys me to no end (and I really believe it harms the chances of getting anyone to understand) when people use the terms OOP and, equally, FP in daily use.
Good example is anyone, ever , saying “look, in FP we have map/reduce and for loops are bad”. It’s just bizarre to think that was ever a real point. Luckily, today all languages have it either in the language or via libraries so we’re past that, but still.
And... for people writing testable code, doing a larger and larger part of their code as pure functions have been standard thinking in corporate Java land for a long time now.
So... there are lots of interesting discussions to be had, but not hidden behind “FP” and “OOP”.
Last part of the rant - I really like Eric Normands podcasts (hmm, long time now?). He is good at the nuances and degrees but also at times falls for the easy trap of saying “ it in OOP it’s like this”.
Is the clojre.core/inst?
simply checking if its argument is an instance of a Java object (assuming I am on the JVM). Just wanted to confirm my assumption. I looked at the source code but was no wiser 😞
https://clojuredocs.org/clojure.core/inst_q
from my reading it checks to see if the argument satisfies Inst
a protocol. and (-> Inst :impls keys) lists java.util.Date and java.time.Instant as two implementers of this protocol
And others may choose to extend the Inst protocol to other types in their programs, or for time-related types they create.
I am not clear if all java objects satisfy the Inst
protocol. If it is just specific Java classes (or other types) I guess I can test them as I make use of them in applications I write. But then curious as to why any type would implement the Inst
protocol if its quite selective.
the protocol doesn't care, and it's not generically possible to say "what are all the implementors of this protocol?"
You can check all of the JVM classes the implement the Inst protocol at this moment using the technique that dpsutton showed, true?
this doesn't cover metadata protocol extensions
(-> Inst :impls keys)
from several mins ago
inst?
doesn't tell you anything about what you can do with the object, except call inst-ms
on it
I am not saying you want to dig into the internals that expression uses in lots of production code. Just if you are curious and doing some poking around/debugging at the REPL, wanting to know what is going on.
I am looking at predicates with clojure.spec right now, but it the value of a type an instance is still to click. I assume its so that you can satisfy the predicte, it seems highly generic though
Ah, i missed the (-> Inst :impls keys)
code from dpsutton, as it wasnt highlighted... 🙂
its very useful, thanks
understood. It is at best a partial list of JVM classes that implement the protocol.
I have a much better context as to where this fits in (although still need some hammock time around the why aspect). Thanks all.
there is a spec generator hooked into the inst?
predicate, and it returns a generator of java.util.Dates
clj -A:convenient
Clojure 1.10.2-alpha1
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (require '[clojure.spec.gen.alpha :as gen])
nil
user=> (s/gen inst?)
#clojure.test.check.generators.Generator{:gen #object[clojure.test.check.generators$such_that$fn__558 0x78d6447a "clojure.test.check.generators$such_that$fn__558@78d6447a"]}
user=> (gen/generate *1)
#inst "1970-01-03T09:07:10.724-00:00"
user=> (class *1)
java.util.Date
which is the easiest way to format a js/Date?
I did it using moment.js (.format (moment %) date-format)
I’d avoid moment.js since its API is mutable. for a js lib I prefer date-fns, but there might be good cljs libs too (haven’t had chance to try them out yet)
there are also a few functions in goog DateTime, but not a proper formatter https://google.github.io/closure-library/api/goog.date.DateTime.html
thanks @UPH6EL9DH and @U051SS2EU, I’ll take a look
I did it using moment.js (.format (moment %) date-format)
Hi I have this vector
[{:key "document_env", :value "teste"} {:key "document_env2", :value "teste2"}]
How can I transform into a map like this:
{"document_env" "teste" "document_env2""teste2"}
?There are multiple ways to do it, but this is one:
user=> (def d1 [{:key "document_env", :value "teste"} {:key "document_env2", :value "teste2"}])
#'user/d1
user=> (into {} (map (juxt :key :value) d1))
{"document_env" "teste", "document_env2" "teste2"}
This is another:
user=> (into {} (for [m d1] [(:key m) (:value m)]))
{"document_env" "teste", "document_env2" "teste2"}
Thanks a lot @andy.fingerhut!
Didn’t know this function: juxt
🙂
NP. juxt
is certainly not necessary to achieve the result, of course, but sometimes nice to see multiple ways to do the same thing.