Fork me on GitHub
#beginners
<
2019-10-28
>
sova02:10:45

Hi, compojure destructuring is my topic, and my question is ... what's the best delimiter to use between vars (for GET requests) ?

sova02:10:51

I end up having a URL likez

sova02:10:57

pardon that Z...

sova02:10:39

http://site.com/S1&amp;L2&amp;P3 -> section 1 lesson 2 part 3... but I'm wondering, is there a better way?

sova02:10:14

I think I figured it out with /x=foo&z=bar kinda deal

sova02:10:28

Anybody got any questions or puzzles or problems that need addressing 😄?

nate_clojurians03:10:08

pretty sure / is the best delimiter. /section/1/lesson/2/part/3

nate_clojurians03:10:03

not sure of the context of compojure specifically but that's the most common pattern I've seen

alidcastano04:10:34

hi is it possible to re-export a variable/function from a module? i.e. if you want a wrap or alias a library globally

didibus05:10:10

Using import-vars

alidcastano06:10:34

@didibus thanks for the link. is it compatible with clojurescript / cljs-shadow?

andy.fingerhut06:10:32

I am pretty sure that the potemkin library is Clojure/JVM only, not Clojurescript.

andy.fingerhut06:10:16

If you mean something like "I have a library with 3 namespaces, and I want the namespace foo to have a public function x that is identical to function y in namespace foo.a.b.c", then one way would be to write this expression in namespace foo: (def x foo.a.b.c/y).

andy.fingerhut06:10:52

namespace foo would also need to require foo.a.b.c

alidcastano06:10:27

yes, that's what I ended up doing for regular declarations but that approach unfortunately isn't working with macros

alidcastano06:10:20

@andy.fingerhut is there a way to rexpose/redeclare macro in a new newspace? i even tried wrapping the macro but doesn't seem to exihbit same behavior

seancorfield06:10:39

If the macro expands to use symbols that were in the original namespace, it may well fail if you try to export it via your namespace. You might have to re-export the symbols that it expands to.

seancorfield06:10:41

After using Potemkin and similar techniques in the past, I've sworn off that approach -- it has a number of weird edge cases and it's usually a bad idea, in my opinion.

alidcastano07:10:07

@seancorfield yeah, coming from js land, I developed a habit of wrapping a library before exposing it in my application. doesn't seem like that's recommend in Clojure? do you just manually write all dependencies in all files?

alidcastano07:10:37

this is an example of what im trying right now, figured if i wrapped it just as I would a function it wouldn't be a problem

(ns ui
(:require [hx.react :as hx]))

(defmacro defnc [display-name props-bindings & body]
  (hx/defnc display-name props-bindings body))

seancorfield07:10:05

It's not really idiomatic in Clojure to wrap things like that.

seancorfield07:10:18

Some libraries do it internally, just to publish an API from functions based in multiple namespaces, but mostly folks expect to require all the namespaces for functions they need to use.

seancorfield07:10:22

I'm not sure why folks would do that sort of thing in JS -- what supposed benefits does it have?

seancorfield07:10:46

In Clojure, we prefer to be explicit about dependencies rather than try to hide them...

alidcastano14:10:07

not so much about hiding, but trying to be control of what you expose to your application i.e. if you want to upgrade a package but there's an API change, or you want to add an enhancement to a function or macro and have it take effect everywhere in your app though in general, I feel that it's useful to also trim down unnecessary dependency declarations - i.e. right now im using a package for react that has components and hooks declared separately so that's two require statements whereas with regular react it would have been one

ozfraier07:10:49

Hi, I'm trying to use a java class method from clojure, but for some reason it doesn't identify the field, here are the details: I've already succeded calling a previous method doing (.connect master) for the variable master I've looked up the instance's methods using (vec (.getMethods (.getClass master))) and found the method I wanted to call - sendRequest:

#object[java.lang.reflect.Method 0x279701e8 "public java.util.concurrent.CompletableFuture com.digitalpetri.modbus.master.ModbusTcpMaster.sendRequest(com.digitalpetri.modbus.requests.ModbusRequest,int)"]
 
trying to call it with (.sendRequest master) resulted in an error:
1. Unhandled java.lang.IllegalArgumentException
   No matching field found: sendRequest for class
   com.digitalpetri.modbus.master.ModbusTcpMaster

            Reflector.java:  397  clojure.lang.Reflector/getInstanceField
            Reflector.java:  440  clojure.lang.Reflector/invokeNoArgInstanceMember
                      REPL:  119  crystal.core/eval18742
                      REPL:  119  crystal.core/eval18742
             Compiler.java: 7176  clojure.lang.Compiler/eval
             Compiler.java: 7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  665  clojure.core/apply
                  core.clj:  660  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  142  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  171  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  170  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run 
I'll be grateful for any insight on this :-]

seancorfield07:10:18

This com.digitalpetri.modbus.master.ModbusTcpMaster.sendRequest(com.digitalpetri.modbus.requests.ModbusRequest,int) says it expects an int argument so (.sendRequest master 42) (or whatever) would be the correct call.

ozfraier07:10:13

Thank you! the problem was with the arguments, needing a request and an int, but I didn't format the call correctly when I first tried, so incorrectly thought the problem was with accessing the method

sreerama.naga09:10:26

Looking for code snippet, which can return the clojure.lang.PersistentTreeMap by removing the key from it. I have an object "myTreeMap" (of type clojure.lang.PersistentTreeMap) this contains 2 keys (1 and 10). I want to remove one of the key( assume value also will be removed) say 10 and after removal "myTreeMap" should be with only one key. please suggest

sreerama.naga09:10:03

It is like dissoc + swap!. can you provide the code snippet ?

schmee09:10:52

user=> (dissoc {:a 1 :b 2} :a)
{:b 2}

sreerama.naga10:10:44

This is not changing the state of the clojure.lang.PersistentTreeMap object.. can you please provide code snippet by using swap! ?

sreerama.naga09:10:39

can we use the same code in the .clj file ?

sreerama.naga09:10:57

PersistentTreeMap is immutable.. so we need to write a code which can swap the exisitng myTreeMap which weill be after removing the key 10.

schmee10:10:14

Clojure maps are immutable, you can’t mutate the them. they always return a new instance

schmee10:10:26

if you want something similar to mutation you need to use an atom:

user=> (def a (atom {:a 1 :b 2}))
#'user/a

user=> @a
{:a 1 :b 2}

user=> (swap! a dissoc :a)
{:b 2}

user=> @a
{:b 2}

sreerama.naga11:10:29

thank you! If I want to verify whether :a exists or not, how to do that? tried with (contains? a :a), it gives error as "IllegalArgumentException contains? not supported on type: clojure.lang.Atom "

dharrigan11:10:12

You have to dereference the atom

dharrigan11:10:26

(contains? @a :a)

sreerama.naga10:10:37

Thank you for your patience and help!

anikchy.cuet9310:10:44

How to make chrome extension using clojurescript? can anyone give me some guidelines about that?

danieleneal10:10:50

I think there is a shadow-cljs build mode for chrome extensions-

danieleneal10:10:54

I haven’t tried it though

danvingo15:10:21

Hello, I have a basic question regarding namespace aliases, I'm wondering why this code (x.Element) doesn't resolve:

$ clj
Clojure 1.10.1
user=> (require '[clojure.data.xml :as x])
nil
user=> x.Element
Syntax error (ClassNotFoundException) compiling at (REPL:0:0).
x.Element
user=> clojure.data.xml.Element
clojure.data.xml.Element

andy.fingerhut15:10:06

Namespace aliases do not work for class names.

andy.fingerhut15:10:33

I am pretty sure Element is a class name?

danvingo15:10:25

so that class would have to be imported?

andy.fingerhut15:10:19

You can use full-path class names with no import statements at all, if you wish. import enables you to refer to a class by shorter names, yes.

danvingo15:10:34

ok great, thank you

danvingo15:10:53

I'm curious why alias don't work with classes. Any reason in particular?

hiredman15:10:20

Don't use import, use the factory function, x/->Element

danvingo15:10:06

ah, now it makes sense - thank you

hiredman15:10:38

deftype and defrecord also generate factory functions, which are a good habit to get into using because a not uncommon error is importing the class without requiring the namespace

danvingo15:10:23

i see - I think the missing piece for me was the difference of referring to java classes vs vars in a namespace

papachan16:10:23

wow didnt knew about this feature to create a starter project:

clj -Sdeps '{:deps
              {seancorfield/clj-new {:mvn/version "0.7.7"}}}' \
    -m clj-new.create \
     \
    hello/core

seancorfield17:10:02

@papachan clj-new knows how to run Leiningen and Boot templates as well (but those will generate whatever is in the template so usually project.clj and build.boot respectively).

seancorfield17:10:59

Or are you just expressing surprise over clj-new's ability to run a template from GitHub? (it also knows about :local/root since it uses tools.deps.alpha like clj/`clojure does).

papachan17:10:05

Yes. Didnt know how to generate a quick template from clj command line. And your clj-new is very useful!

alexpashkov12319:10:51

Hi, I’ve ran into a bit unexpected behaviour with

reify
macro. I have builder function that during initialisation (just before reify) can throw an exception. For some reason, that exeption is being caught and only shows up when one of the methods of the reified object is called. Is it done intentionlly and I’m missing something?

bfabry19:10:53

map returns a lazy sequence

alexpashkov12319:10:11

Ah crap, thanks

bfabry19:10:12

so that isn’t evaluated until something consumes subpatterns

andy.fingerhut19:10:34

mapv is strict, if that helps

andy.fingerhut19:10:04

Having subpatterns inside of the let is useless in either case (map or mapv)

alexpashkov12319:10:16

@andy.fingerhut why? Wouldn’t I be calculating it on every call then?

andy.fingerhut19:10:18

not sure if you put it in the body just before the call to reify in hopes of causing it be evaluated fully, but either you use lazy map, and having subpatterns there still does not cause it to evaluate fully, or you use mapv, and then having subpatterns in the body doesn't help

alexpashkov12319:10:35

That was my intention

alexpashkov12319:10:42

to have it calculated once

alexpashkov12319:10:00

but I got a bit rusty with Clojure and forgot about lazyness 🙂

andy.fingerhut19:10:09

The expression (->> s subpatterns-strings ...) is evaluated on every call to the function new-pattern as you have written it

andy.fingerhut19:10:55

It is not re-evaluated on every call to the recognize method of the object returned by reify

alexpashkov12319:10:57

ok, seems like I should check my understanding of laziness

andy.fingerhut19:10:24

Have you programmed in Haskell before?

alexpashkov12319:10:46

just regular stuff like Javascript and Golang

andy.fingerhut19:10:47

If not, no worries. Just wanted to know your background in order to know what things might help explain Clojure laziness.

andy.fingerhut19:10:14

In Clojure, many functions return a lazy sequence, including map filter and a dozen or two others.

andy.fingerhut19:10:00

Unless you force them to be evaluated, only as many elements as you actually use are evaluated, when they are needed. (sometimes a few more elements are evaluated ahead of that)

alexpashkov12319:10:35

ok, so function supplied to map would be called the first time the elem is actualy used?

alexpashkov12319:10:48

and the that value would be re-used in later usages?

andy.fingerhut19:10:41

yes. And sometimes the function will be called for a few elements after the latest one you have ever accessed, but even then the function will be called at most once per input element of the sequence given to map

alexpashkov12319:10:38

ok, got it. you were extremely helpful, thanks

andy.fingerhut19:10:01

If you want to force any of the functions that return lazy sequences to immediately do all of their processing, which requires the time and the memory to store all of the results, you may wrap the call inside of (doall ...)

alexpashkov12319:10:24

in my case mapv would also do, right?

andy.fingerhut19:10:51

I mention doall because it works for any expression that returns a lazy sequence, including a call to map filter etc.

alexpashkov12319:10:28

@andy.fingerhut got it, thanks

andy.fingerhut19:10:40

you are welcome