This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-23
Channels
- # announcements (26)
- # babashka (8)
- # babashka-sci-dev (3)
- # beginners (93)
- # biff (44)
- # calva (1)
- # cider (7)
- # clj-kondo (13)
- # cljdoc (1)
- # clojure (121)
- # clojure-australia (2)
- # clojure-europe (18)
- # clojure-nl (1)
- # clojure-norway (5)
- # clojure-uk (1)
- # clojurescript (35)
- # conjure (1)
- # core-async (2)
- # datalevin (6)
- # datomic (28)
- # emacs (25)
- # events (1)
- # fulcro (5)
- # introduce-yourself (2)
- # jobs (8)
- # leiningen (2)
- # off-topic (13)
- # other-languages (1)
- # podcasts-discuss (1)
- # polylith (7)
- # rdf (6)
- # re-frame (1)
- # reagent (53)
- # releases (3)
- # rewrite-clj (7)
- # scittle (5)
- # shadow-cljs (63)
- # specter (1)
- # squint (5)
- # tools-build (5)
- # xtdb (7)
Hello, I currently learning ClojureScript with Reagent and tailwind, and hot reload doesn't work, how can I fix it? here's my core.cljs
(ns frontend.core
(:require [reagent.core :as r]
[reagent.dom :as rdom]
[frontend.views :as views]))
(defn ^:dev/after-load start
[]
(rdom/render [views/app]
(.getElementById js/document "app")))
(defn ^:export main
[]
(start))
doesn't work how? are there some errors in the console?
There's no errors, I run
npx shadow-cljs watch frontend
and when I save a file(views/app), changes don't affect the web page on reloadand every time when I change something I need to restart the server to see the changes
probably you'll find answer quicker if you ask in #shadow-cljs )
thanks, I'm new to this Slack:sweat_smile:
How do you do development with a remote machine? Do you use sshfs/samba to map remote folders to local?
I'm a emacs user, so I can use the excelent tramp mode (some tricks [here](https://willschenk.com/articles/2020/tramp_tricks/) ) over SSH without mounting anything.
If you want to connect to a running JVM on another machine, you could start the REPL process and use SSH port forwarding to connect your editor from your local machine?
You can have a local checkout and do git operations as you would locally. So long as you can start the REPL with all it's dependencies on the remote machine, you shouldn't notice much difference, right? You can still load whole files over a REPL connection. I guess it depends why you want to use a remote dev machine. Is it too get around CPU or ram limitations locally? Or do you want to access networked resources that are firewalled off from your local box?
What do you mean by "a long string"? With nothing set up, you'd have to type all your credentials and stuff, but with a proper .ssh-config, it's just serveralias:~
the ~colon~ tilde opens a dired in the home folder, you can use auto-complete to navigate as if you're local. I think you could just add a remote project with projectile and jump to it using tramp...
For remote dev work I found emacs in the terminal over https://mosh.org/ runs fantastically. Mosh has 3 main benefits for me: • "Local echo" so no delay in seeing what you have typed • Fast networking using UDP packets - so no TCP delays. • Instant reconnection even if IP address changes You can switch back and forth between remote emacs and local emacs easily (all buffers are still open + repls are running). All the processing happens on the remote machine - so you can use a small and light laptop when travelling. I also use autossh to expose ports and keep them open. Both Mosh and AutoSSH are secured by SSH so they're pretty secure.
I do remote development by sshing into the remote machine(usual a vm) and running emacs there. Been doing that for all my work related development for 10+ years. It was how everyone was encouraged to work at my first clojure job
@U0NCTKEV8 - recommend giving mosh a try for lower latency if your VM is not in the same building.
e.g. I can run portal in a repl on my remote vm and view it using the browser on my laptop
For GUIs that you use infrequently - I've found X over SSH can sometimes be good enough.
I've only recently started using emacs --daemon and emacsclient, and it is pretty great
generally copy stuff and pasting it into a remote text emacs is fine, but copying text from a remote text emacs and pasting it elsewhere can be really annoying
some overly complex code that lets me send a region of text from a remote text emacs to my laptops clipboard
Why is copying from remote this hard? In urxvt selecting the text alone gets the copy done.
if you have multiple emacs windows open you can't select an entire line of the terminal because it will select across multiple windows
even with one window if lines wrap you'll get the \ indicator if you naively copy text from the terminal
I have a terminal full screen on a 1080p monitor, so I usually have at least two buffers open side by side
oh i see. no problem here as i always break long lines. tramp-mode mentioned above also should work.
I've also used nrepl connection over SSH to collaborate with others on a REPL process running on the server, using the Gui version of Emacs and using VSCode Live share feature (very nice feature for real-time collaboration) I've mainly used an AWS VM and Emacs (Spacemacs) although as it's nREPL I could use Neovim, vim, Emacs, Calva, any Clojure editor. https://practical.li/spacemacs/clojure-repl/connect-to-remote-repl.html
Yo, what kind of tools do I have to work with recursive structures? I am trying to convert a fairly simple map structure with a recursive :children
key to a nest :ul :li
Reagent hiccup structure. Currently what I have is
(defn- task->ul [{:keys [id name start end children]}]
[:ul {:key id}
[:li name]
[:li start]
[:li end]
(when children
(map task->ul children))])
This works, but recursion scares me, I have seen walk
and postwalk
but I'm having trouble wrapping my head around them.
I've also thought about the quasi tail-recursive solution with (loop ... (recur
but I'm not sure how to approach it.(def nested-gantt-sample)
{:id "1"
:name "Gantt 1"
:start "2021-01-01T08:00:00"
:end "2021-01-08T17:00:00"
:children [{:id "2"
:name "Gantt 1.1"
:start "2021-01-01T08:00:00"
:end "2021-01-08T17:00:00"
:children [{:id "3"
:name "Gantt 1.1.1"
:start "2021-01-01T08:00:00"
:end "2021-01-08T17:00:00"}]}]}
something like postwalk with a function that calls task->ul on maps would be pretty close given that sample, but instead of the recursive call, just leave children in a state that the walk will do whatever is desired with the entries there (because the postwalk will essentially end up running task->ul on the children by virtue of the walk)
your solution is fine, are you really worried about stack overflow errors ? the tail recursive solution is hard to write with an immutable data structure, perhaps the easiest way is with zippers (you basically need to pass the entire structure and the location as argument to your recursive function)
I was looking at this and didn't see an obvious solution. I agree with rolt, both that I wouldn't worry about this in practice, presuming a gantt chart isn't going to be recursing deep enough to be a problem, and that my approach if I was worrying about this would probably be based around a zipper (but that may be because I've been digging around in zipper land recently). There are a few library options for writing transformations, they may be overkill for this but worth knowing about. • https://github.com/noprompt/meander • https://github.com/redplanetlabs/specter
Is there a way to enforce that to satisfy protocol Foo, an object must also satisfy protocol Bar?
If not, are there any good patterns for making such requirements self-documenting and/or easily discoverable?
For example, if basic usage of a type defined by a protocol also requires implementing INext
, how do I make that known through code, and not just a comment?
I think it's often just done by convention + docstrings/comments. There's some reasoning behind this design decision. I can't remember exactly, perhaps because type hierarchies/inheritance are hard to extend or are too limited in some way. Or just to discourage recreating OO programming when there are better options with FP. I guess you could use clojure.spec to enforce the relationship between two types. Will be interesting to see how others respond
I'm not overly concerned about the enforcement part. I just want something more "in the code" than docstrings or comments, that explicitly demands the minimum requirements.
This is a shot in the dark but is spec not an option here?
I have no idea, but if it's not an existing feature it seems like it could be implemented?
With defprotocol
I am declaring "If you want the behavior of Foo
, you need to implement foo
." Except that's not true, because without bar
, a Foo
is completely broken and useless. But bar
is already of the Bar
protocol.
I know I could use spec at the implementation layer, but at this layer, my only concern is that some implementation will be provided later.
Are you looking for a compile time check? Otherwise you could in your implementation of Foo's methods do something like (foo-method [this] (assert (satisfies? Bar this)) ...)
A compile time check would be "nice to have". My bigger concern is having the code in and around (defprotocol Foo ...)
be self documenting, such that someone reading the code can scan over it and (without reading the comments or docstrings) know that "Ok, to make a Foo
, I need foo
and bar
. So I had better go look at the code for Bar
, too."
I'm not sure I quite follow your suggestion.
Oh. I see. You are suggesting that the implementation can make a runtime check. That's not really the goal. I am trying to get self-documenting code at the interface level, for the sake of someone writing an implementation at a later date.
Why not use schema. Something like this (I didn’t test):
(s/def :my/protocol (s/and #(satisfies? Bar %) #(satisfies? Foo %)))
hm... if method foo of protocol Foo needs method bar of protocol Bar then i would combine those methods under one protocol, either Foo or Bar.
there is no point having a protocol that implicitly depends on another protocol imho
As discussed you can create a runtime check using (and #(satisfies? Bar %) #(satisfies? Foo %))
- with Schema
or Spec
or Assertion
or plain functions that throws an exception.
You probably can't and shouldn't try to make it a compile time exception - you can't be certain that forever the two Protocols are always required together. e.g. a Bar2
could be created that replaces Bar
. Also in clojure you are not forced to implement any methods of a protocol - they are always optional.
> there is no point having a protocol that implicitly depends on another protocol imho The implication is that Bar has meaning without Foo, but Foo does not have meaning without Bar. The most obvious and straightforward example is to depend on any protocol in Clojure core, e.g. Foo must be countable. You don't even have control of the base protocol in that case. But even if you did, that would not make it wise to go messing with it for the sake of the derivative protocol. But then how do you express in the code that Foo must be countable?
> Foo must be countable
The answer in Clojure seems to be either a runtime check or just don't worry about it.
You have to imagine that you release Foo
protocol in a library and then never update it. Today Foo
must also be Countable
, but you can't guarantee that it must be Countable
forever. What if we have a BetterCountable
protocol instead in the future? Your users would still be stuck having to use Countable
too even though no one uses that anymore.
Also a protocol does not force you to implement a method so even if you create a type that implements Countable
- there is no guarantee that count
has been implemented correctly or even at all.
All I really want to something roughly on the lines of...
(defprotocol Foo
{:dependencies
{:count clojure.lang.Counted}
(foo [this] "foo does a thing"))
Ideally this code would imply a check for count
implemented via extend clojure.lang.Counted
when calling satisfies
, though arguments against doing that are totally reasonable.
More importantly, the code itself tells the (human) reader "You need to implement count
(which is currently part of the clojure.lang.Counted
protocol) if you expect the Foo
protocol to work as intended." Specific details about how to implement count
appropriately or why it is needed, can then be relegated to comments/docstrings, or even to docs.
Maybe I need to write simple a macro that just throws away the dependency declaration?> But then how do you express in the code that Foo must be countable?
by using count
method of Counted
interface inside of another method implementation
in general i try to not express that interface or protocol must depend on something. This belongs to implementation
btw schema has variant of defprotocol which might help - https://plumatic.github.io/schema/schema.core.html#var-defprotocol
Protocols are open for other namespaces/developers to use. The idea is not second guess how it could be used, a future developer of the code may thank you! Protocol hierarchies are an OO concept that have limitations and problems associated with them (I gave an example in a previous response). I get what you want to do and have wanted to do the same myself before, but I think your program will probably work fine without the protocol relationship baked in at code/compile time.
But if you do want this then a macro could be a solution as you suggested.
Also someone could come up with InfiniteFoo or RandomProbabilisticFoo that cannot be counted.
I am trying to make a lib where the Protocol is a major part the API. The lib will have at least one reference implementation, but the goal is for the user to be creating fully custom implementations There are 2 cooperating protocols: one describing a state monad and the other a state container. The purpose of the state-protocol is to provide dependable entry points for the state-monad, to know how it is allowed to access and update the state, while leaving the user with complete freedom on generation and traversal of data. So with Foo representing the state container, any particular Foo implementation may or may not use its own protocol methods internally. But if some method is missing, it will break the consuming transformer, and thus the entire API. It needs to be implemented. In essence, a Foo is not a Foo without all of some set of methods, because the simplified definition of a Foo is "a thing that can be correctly transformed by a Foo-managing state monad". It is possible someone could be interested in adding more ways to transform a Foo. But if a Foo cannot be transformed correctly by its corresponding monad, there is zero reason to put your data into a Foo in the first place.
> Also someone could come up with InfiniteFoo or RandomProbabilisticFoo that cannot be counted. As per the explanation above, if InfiniteFoo does not provide the API required by FooTransformer, then it not a Foo.
> btw schema has variant of defprotocol which might help The value-add of schema's defprotocol is type hinting the inputs. A major goal of my protocol is to have as little opinion as possible about the types of the inputs.
do you have some draft pseudocode that can describe how one would use your library? I'm not sure I ever needed just a protocol from the lib so it is hard for me to understand your intention
Schema can give you a hint on how to implement such macro. there are also some "gotchas" in the docstring that could help
I could be wrong, but I don't think I would have much difficulty with the macro as described. Just seems kind of gross to write a macro who's entire purpose is to throw code in the garbage. 😄
I'll think about how I could meet in the middle at a minimalst example halfway between Foo and the real (very much in flux) codebase.
try it :) some times Clojure can give very hard time when one want something "unusual"
btw. your Foo-managing state monad suppose to be provided from your library? if so then it could have checks if an object implement specific protocol or even protocol method
Good point. ✅ That could cover the enforcement side, if I decide it is worth it. Does not, in my opinion, cover the self-documenting concern. If I am assuming that reading the comments is too much to expect from the user, then digging through the other protocol for runtime checks is clearly even worse.
Thanks for your detailed description. Your description does not:
• explain why it is exempt from the BetterCountable
scenario that I mentioned.
• Or exempt from someone wanting to create a type that only takes one of your protocols e.g. for unit testing.
• Or from the fact that a protocol does not guarantee that the associated methods are actually implemented or correct (which seems to make it pointless to force the protocol).
Even your specific usecase overcomes the above, can you see that there are lots of scenarios where protocol hierarchies are a bad idea and should be avoided?
You can easily create a runtime function that is "opt in."
(defn is-foobar?[s](and (instance? Foo x) (instance? Bar x))
This allows users to opt in to your check without being forced at compile time.Yeah. Your argument against compile-time checking makes sense, as Clojure currently stands. In my description, BetterCountable
should be fine so far as it means that a Foo implementation will reliably include a`count` method. My primary concern, again, is that the code of (defprotocol Foo ...)
is somehow providing self-documentation that it needs certain methods, our example being`count` (with the general expectation that it would come from implementing certain existing protocol(s), in this case Counted
).
As for the generic argument against hierarchies, I see no reason that BetterCountable
could not declare provides Counted
. But, of course that is not a currently existing feature of the language.
Excellent - the language is extensible through macros if you do want to add the compile time checks. But I just felt it worth highlighting that this is likely a case of "YAGNI" - lots of Clojure code works fine without it - and probably your use case too.
You could always use composition instead of inheritance and have foo take a bar as one of its arguments. If you really want to have them be the same object, then you could always provide a function that has one less arity and passes the same object to foo twice? Or am I misunderstanding the problem?
I am extending nil
with the protocol to get nil
punning behavior. So no, I cannot get that from composition.
in Clojure you can't extend primitive, can you?
i mean extend
function
I have not specifically tried extend
function. But it works with fine with extend-protocol
and with extend-type
, so I assume that translates to also working with extend
.
i can be easily wrong) do you mind share how you extend nil with protocol?
(defprotocol IFoo
(foo [this]))
(defrecord Foo [x]
IFoo
(foo [_] x))
(foo (->Foo "foo")) ; foo
(foo nil) ; Execution error
(extend-type nil
IFoo
(foo [_] nil))
(foo nil) ; nil
thanks