Fork me on GitHub
#clojure
<
2018-01-13
>
rufoa00:01:37

@bj: try-let is my project šŸ˜„ I'm not aware of a better ready-made solution to the problem. I wrote it to scratch my own itch a couple of years ago, but it should work fine

caleb.macdonaldblack02:01:39

How can I get with-redefs to work on a private function in another namespace?

andy.fingerhut02:01:49

(with-redefs [my.other.ns/fn-name (fn ...)] ...) is working for you? I was able to get that working in a REPL session test

caleb.macdonaldblack02:01:43

@andy.fingerhut I didnā€™t for me. Ill have another go and try to see what Iā€™m doing wrong

caleb.macdonaldblack02:01:32

Calling the fn directly works for me. My function Iā€™m wanting to redefine is in a partial though

caleb.macdonaldblack02:01:58

(def my-partial (partial fn-name :foo))

caleb.macdonaldblack02:01:32

fn-name is private in that namespace and redefining doesnā€™t seem to work

andy.fingerhut02:01:39

My REPL test went like this, in case it helps you (starting from user namespace): (ns foo) (defn- bar [x] (inc x)) (ns user) (#'foo/bar 10) ; returned 11

andy.fingerhut02:01:48

(with-redefs [foo/bar (fn [x] (* x x))] (#'foo/bar 10)) ; returned 100

caleb.macdonaldblack02:01:24

Yea that works for me too.

caleb.macdonaldblack02:01:46

I think the with-redefs wont work for me here though

andy.fingerhut02:01:47

You area trying to with-redefs my-partial ?

caleb.macdonaldblack02:01:23

yea, Iā€™m not atually invoking the function Im redefining. Im invoking the return value from partial

caleb.macdonaldblack02:01:09

And the partial is invoking what I pass into it.

andy.fingerhut02:01:28

Again, not sure if it helps, but continuing my sample REPL session from above: (def mybar (partial #'foo/bar 10)) (mybar) ; returned 11

andy.fingerhut02:01:36

(with-redefs [foo/bar (fn [x] (* x x))] (mybar)) ; returned 100

andy.fingerhut02:01:37

Is your def of my-partial in the other namespace, and marked private?

caleb.macdonaldblack02:01:57

the partial is in the same ns as the private fn im wanting to redefine

caleb.macdonaldblack02:01:26

Im thinking the functions visibility is irrelevant here

seancorfield02:01:50

And because it uses (partial private-fn ...) instead of (partial #'private-fn ...) you're getting the original value compiled into the partial expression -- so there's nothing to redefine.

seancorfield02:01:29

Per @andy.fingerhutā€™s example, the partial call needs to use the Var not the symbol to give you the extra level of indirection.

andy.fingerhut02:01:12

But if fn-name is in another namespace and is private, how do you even refer to it in the partial call, without prefixing it with #' ?

caleb.macdonaldblack02:01:29

yea I need to use the symbol

seancorfield02:01:29

> the partial is in the same ns as the private fn im wanting to redefine ^ This

andy.fingerhut02:01:56

ah, sorry, missed that.

caleb.macdonaldblack02:01:21

(def my-partial (partial fn-name :foo)) doesnā€™t work and (def my-partial (partial #'my.other.ns/fn-name :foo)) does

seancorfield02:01:57

The former has the (partial fn-name :foo) compiled at namespace load time and bound to the Var my-partial. And fn-name is evaluated to the value it has -- its underlying fn value.

caleb.macdonaldblack02:01:16

@andy.fingerhut @seancorfield Thanks for the help guys! I understand too now which is awesome!

seancorfield02:01:17

The latter is still compiled but uses a Var instead -- for the reference to fn-name -- and maintains the indirection.

caleb.macdonaldblack02:01:51

so a symbol like fn-name will evaluate to its current value and later when it is called it will invoke whatever it initially evaluated as. By using the #'some.ns/fn-name, when invoked later will invoke whatever is currently defined for that symbol?

andy.fingerhut02:01:10

I think you've got the right idea. I believe that the (partial fn-name :foo) expression without the #' captures and uses the current value that the var fn-name at the time that partial expression is evaluated, and changing the value of the Var fn-name later does not change the value of the partial expression.

andy.fingerhut02:01:49

(partial #'fn-name :foo) captures and stores the value of #'fn-name, a pointer/reference to the Var fn-name, not to its value.

andy.fingerhut02:01:34

As a convenience, Clojure Vars implement an interface in the internal Java implementation that causes their current value to be looked up and called.

seancorfield02:01:19

Right, it only matters when you use a function name in an expression, rather than in another function. In an expression, everything is evaluated, inside a function it's just compiled. (well, slight simplification there but...)

seancorfield02:01:39

(consider that top-level def forms are evaluated when the namespace is loaded so your :require causes the evaluation)

caleb.macdonaldblack03:01:40

Right so invoking the function (wrap in an anonymous function) will look up the value of the symbol and would work with redef and no #ā€˜. But passing the symbol for the function straight in with #ā€™ doesnā€™t? Am I on the right track?

seancorfield03:01:31

I'd have to see the exact code before I answered that.

caleb.macdonaldblack03:01:38

yep thatā€™s what I meant.

andy.fingerhut03:01:50

In case the details might be of interest, the file Var.java in the Clojure implementation defines class Var to impement interface IFn, and IFn is the interface that Clojure functions implement.

qqq13:01:18

is there a way to define a wrapper around clojure.test/is where it runs in cloljure modce, but is a no-op in clojurescript mode (this is . clojuretest/is in a *.cljc file)

gonewest81814:01:27

Something like #?(:clj (is ... )) ?

mbjarland17:01:47

is there an idiomatic naming convention for functions which return functions?

noisesmith17:01:24

sometimes they start with an f (`fnil`) or end in -fn (`some-fn`)

mbjarland17:01:10

@noisesmith ok, thanks, Iā€™ll run with that. Now that I look at that I think I might prefer the leading f. Less of an afterthought, more in your face

ivana19:01:13

Hello. Last week I registered on http://www.4clojure.com and up to date i'm solving the bigger part of it tasks. But. I f I solved the task, I even can not to see any solutions of other members (that is possible on Codewars, for example) - I must follow each of choosen members personally. Why I write this here? Can you suggest me some (3-5) members, that I can follow to learn good Clojure-way style of problem solving and code organize? Thank you.

manutter5119:01:32

I havenā€™t visited 4clojure in a while, but as I recall, when you solve a problem there is a link in the ā€œcongratulationsā€ text that you can click to see other peopleā€™s answers.

fiddlerwoaroof19:01:32

If I wanted to read in a bunch of parquet files and fiddle with the data in them, what's the lightest-weight way to do that?

ivana19:01:15

@manutter51 unfortunately only this >You can only see solutions of users whom you follow. Click on any name from the users listing page to see their profile, and click follow from there.

misha22:01:03

chased last one for 20 minutes -_-

(merge-with (fnil - 0 0) {:a 0} {:a 2})
=> {:a -2}
(merge-with (fnil - 0 0) {:a nil} {:a 2})
=> {:a -2}
(merge-with (fnil - 0 0) {} {:a 2})
=> {:a 2}

noisesmith22:01:33

right, if there's no matching key the merging function is never called

misha22:01:31

it is so obvious it this example, but was not that obvious in

(merge-with
  (fnil - 0 0)
  {:gold 478 :wood 20}
  {:gold 450 :wood 20 :stone 20})
=> {:gold 28, :wood 0, :stone 20}
especially being pre-blinded with clever fnil use

misha22:01:20

actually, most of the time debugging was spent on getting to the merge-with call, because this call is from days ago, and was considered correct opieop

noisesmith22:01:59

if you had used merge-with + and negative numbers, you wouldn't have this issue - but I still think that merge-with is a poor match for this algorithm

misha22:01:11

replaced it with reduce-kv

misha22:01:49

and it was faster to use merge-with - than to update 600 lines of edn with - in prices : )

qqq23:01:43

does #?(:cljs ... #clj ... ) mess up line numbers? the line numbers seem to not match up with my eidtor line numbers

qqq23:01:57

is there something that provides "core.async channels" over websockets? I don't need the full power of core.async, what I want is a channel taht: 1. provides FIFO 2. at most once delivery 3. back pressure 4. wocks cljs <-> clj over websockets

tbaldridge01:01:23

Most of that is impossible with websockets

tbaldridge01:01:10

Code a protocol to the web socket api and youā€™ll be much happier

tbaldridge01:01:42

Also consider a pull based model, as those are much easier to scale and maintain than a push based model

tbaldridge01:01:59

See Kafka vs RabbitMq for an example

qqq02:01:16

@U07TDTQNL: what's the logic of "most of that is impossible with websockets"

qqq02:01:08

intuitively, client side: keep a queue of items to be delivered send first item over websocket server side: wait for item on receive, send ack if item already recieved (check counter), ignore counter increments, so server side needs only store "value of last counter"

qqq02:01:19

I'm trying to abstract out the mess of disconnections / having it auto reconnect websockets

tbaldridge02:01:47

Eh, I mis-read "at most once" as "exactly once". But aside from that, what you're talking about here is TCP over Websockets (over TCP).

tbaldridge02:01:36

And in the end it's just not something that works well. Websockets don't implement back pressure, so you have to implement that as well in the user layer, which slows things down even more.

tbaldridge02:01:53

When a client disconnects it could re-connect through a different server in a load-balanced cluster

tbaldridge02:01:00

All this goes away in a pull-based model.

tbaldridge02:01:38

1) Client connects 2) Server replies "there are 2000 available messages" 3) Client says "well I have 3 so far, so get me the next 100" 4) Server replies "here's 4-104, btw, you have 10000 available messages" 5) Client says "I'm behind, let me skip forward to message 9950 and get me 50 messages" 6) goto 4

tbaldridge02:01:27

This also scales well over slower bandwidth systems, and reduces the amount of tracking the server has to do. Infact the entire protocol is stateless and can be implemented over HTTP. Which has the nice side-effect of working in places where websockets don't (corporate networks)

qqq02:01:33

I'm working on an "editor" where: * frontend = DOM / SVG on localhost:8000 * backend = clojure + jvm + ring + websockets * all "logic" is done in backend * "frotnend" is just (display this SVG/DOM, and routes all keystrokes / mouse events to backend) * this will be fully scriptable in clojure so now, I need a way for clients to "push" these keyboard / mouse events to the localhost webserver

qqq02:01:55

admittedly, since everything is localhost, maybe I shouldn't worry about disconnections at all