Fork me on GitHub

hey folks, can you guys help me to understand this sentence: symbols inside a syntax quote are fully resolved from ?


It means that a symbol like = will be replaced with clojure.core/= in the macro expansion


unless there is some other definition of = in another namespace that shadows the one in clojure.core


You could write all of your Clojure code like that explicitly if you wanted to, but for obvious reasons most people do not.


this (defmacro m [] (let [x 1] x))` doesn't work, but this (defmacro m [] (let [x# 1] x#))` does, why?


this `(defmacro m [] `(let [x 1] x))` doesn't work, but this `(defmacro m [] `(let [x# 1] x#))` does, why?


Without the # after the x symbols, the backtick (`) around the (let [x 1] x) causes them to be replaced with user/x (if you are doing this inside of the user namespace)


Try typing (let [user/x 1] user/x) at the REPL and see what happens.


hunnnn i got the same error


now i really got it, at least i think i really got it 😄


so when i put the # does really happening under the woods?


evaluating x# to something else?


in the documentation they said # generate a unique (unqualified) symbol


what is an qualified and unqualified symbol? can i have an example of each of them?


namespace qualified is what it refers to


Try typing this at a REPL, with the backtick in front of it: `(let [x# 1] x#)

👍 5

syntax quoting namespace qualifies all the quoted symbols


Then do it again and see if there is any difference.


x changed to some weird var name


yeah they are


x# causes syntax quote to produce a new gensym (a randomly generate not namespace qualified symbol) which x# will be replaced with for all occurrences of x# in the same syntax quote

👍 5

syntax quote is mostly useful as a facility for writing macros, and those two features (gensyms and namespace qualification) help with what is called macro hygiene


macro hygiene is an old problem in lisp macro systems, so if you google it you can find lots of information about it, including solutions to it that other lisps uses, syntax quote just happens to be clojure's


(racket has a lot of really cool facilities for hygienic macros including some really novel stuff around sets of scopes for avoiding symbol capture

👍 5

thank you guys for your explanations 😄


i've learnt something more this night 🙂


hello! I'm new to Clojure and I'm trying to understand the concept of immutability a bit more. on some tutorials I see written that I can't change the value of a map (for example) after it's created, but on on the lein repl I can totally do (def a 1) and then (def a (a + 1)) why isn't this impossible?


a is just a pointer, if in the C/C++ context, when (def a 1) it points to a heap-block with the value 1, and when (def a (+ a 1)) it points to another heap-block with the value 2. The difference is in most mutable programming context, there is only one heap-block.


Hi @slack.jcpsantiago! TL;DR immutability doesn’t simply mean that you can’t change anything in Clojure after defining. The questions is more broad. In Clojure there’s indirection between symbols and the values they refer to. When you call (def a 1) you’re actually binding symbol a in current namespace into a var with initial value of 1. You can override these bindings at any time, which provides tons of flexibility when you need it. When talking about immutability in Clojure, we usually talk about the immutable data structures (maps, vectors, sets..) that Clojure has out-of-box. These data structures provide certain guarantees, for instance that different threads see consistent view of values when the data is accessed. This makes programming a lot easier to reason about in many situations.


In languages with mutable collections, you could have 10 pointers/references/variables/etc. all "point" at the same set/list/dictionary/etc., and if you modified that collection through any one of those 10 references, it would also become modified when viewed through any of the other 9.


ah I get it


Clojure has mutable things, like Vars, atoms, and refs, but they are separate from the immutable values like vectors, lists, sets, and maps. In Clojure, you can have 10 Vars all point at the same vector, but if you assign one of those 10 Vars to a different vector, it does not affect any of the other 9.


thanks guys, that makes sense


how in Clojure get any nested map like it does not matter which level it is at. EXAMPLE: {: k {:l {:m 5}}} and I need to get :m ,without knowing exact path


So you know that somewhere inside your nested maps there’s a key named :m but you don’t know exactly where?


If yes, I’d either use tree-seq or something from clojure.walk for this.

👍 5

if i were building a rest api, is there a particular lib that the community seems to be coalescing around? or is "http-kit with ring handlers" just as valid/supported/whatever as anything else? like...duct?


I think compojure-api is a popular and well supported option. There’s a lot of choice though


yeah, the choice is the "problem" - a little bit of paralysis 🙂


IME starting with anything is fine


try and pick something that looks relatively simple. e.g. ring and http-kit


(for your first project)


I know that there is no obvious answer to this question, but what makes (clojure) code a production code? Some words come to mind: tested, documented, clean code, good design. It would be great to start a discussion on this topic


what makes code production code is it being in production

😎 5

good to know. thanks


@leandrotk100 If you're asking what are some good practice for high quality code in regards to Clojure. I'd say it's pretty similar to any other language. Try to have good behavioural test coverage of your main features. Try to have good unit test coverage. Try to have some generative property based tests when possible. Make sure you extensively tried out your code in a repl. Have one or more persons code review your code. Use eastwood to lint your code base for common mistakes. Leverage existing libraries when possible. Keep things simple and decomplected. Document tricky logic. Perform some load testing. Take some time to think about possible security attack vectors and make sure you have them mitigated. Do some A/B testing, and staged deployments. Etc.


how can I sort-by the quotient of two keys?


i have a :ratings-total and a :number-of-ratings and i'd like to sort by the quotient


@sova (sort-by #(/ (:ratings-total %) (:number-of-ratings %)) coll)


Hi I'm learning clojure after having 7 year of ruby on rails background. I have 2 questions: 1) Rails adds created_at and updated_at columns in every db table and fills these columns automatically every time db record is created/updated. Is there something similar for Clojure? 2) In rails migrations are written in ruby DSL ( I'm not defending this approach, I don't say that it's good. But I see that in most of clojure libraries migrations are written in raw SQL. I'm wondering, is there some point in writing raw SQL migration that I don't see? May be writing DSL migrations has disadvantages. Should I forget about using DSL in migrations? It seems I can do dsl by using using create-table-ddl

(ns dbexample
  (:require [ :as jdbc]))

(def db-spec ... ) ;; see above

(def fruit-table-ddl
  (jdbc/create-table-ddl :fruit
                         [[:name "varchar(32)"]
                          [:appearance "varchar(32)"]
                          [:cost :int]
                          [:grade :real]]))
I'm confused little bit because I didn't find rails like framework for clojure with everything I need out of the box and good documentation. And I didn't find book or blog articles for rails developers. There are such books for rails, for example "Rails for PHP Developers". But I didn't find such books for clojure.


@sigmaray I have the same convention (I call the columns created and updated). But I do it manually in Postgres with a default value on the table definition and change the _update column on, well, update queries


@sigmaray For migrations I use migratus.


For writing SQL queries I use HugSQL. Just FYI. There are other ways to do it.

Lennart Buit20:01:47

Yeah, there is also HoneySQL I think it is called


@sigmaray if you’re looking for something close to Rails, is your closest bet.


im in the process of migrating a Rails application to a clojure backend


we’re using hugsql instead of an ORM and for database migrations we’ve chosen migratus


Then we’ve put the clojure api as a proxy in front of the rails app. it routes all unknown routes to the rails app.


@sigmaray You can also take a look at the Luminus framework (by the author of migratus). Start off with the default app and make changes to tailor to your needs as you go along. Clojure folks generally prefer to use several libraries together rather a particular framework, but Liminus can get you started. There is also a #luminus channel for discussions if you need help.


hi, I'm using the cli-maticlibrary to build a cli app, tried to use GraalVM to make it's execution faster, however I got the following error:

No native library is found for and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64


If I run standalone jar file, everything works fine. The full stack error:

** ERROR: **
JVM Exception: #error {
 :cause No native library is found for and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64
 [{:type java.sql.SQLException
   :message Error opening connection
   :at [java.lang.Throwable <init> 265]}
  {:type java.lang.Exception
   :message No native library is found for and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64
   :at [java.lang.Throwable <init> 265]}]
 [[java.lang.Throwable <init> 265]
  [java.lang.Exception <init> 66]
  [org.sqlite.SQLiteJDBCLoader loadSQLiteNativeLibrary 333]
  [org.sqlite.SQLiteJDBCLoader initialize 64]
  [org.sqlite.core.NativeDB load 56]
  [org.sqlite.core.CoreConnection open 211]
  [org.sqlite.core.CoreConnection <init> 76]
  [org.sqlite.jdbc3.JDBC3Connection <init> 25]
  [org.sqlite.jdbc4.JDBC4Connection <init> 24]
  [org.sqlite.SQLiteConnection <init> 45]
  [org.sqlite.JDBC createConnection 114]
  [org.sqlite.JDBC connect 88]
  [java.sql.DriverManager getConnection 664]
  [java.sql.DriverManager getConnection 208]
  [$get_driver_connection invokeStatic jdbc.clj 254]
  [$get_driver_connection invoke jdbc.clj 233]
  [$get_connection invokeStatic jdbc.clj 401]
  [$get_connection invoke jdbc.clj 257]
  [$db_query_with_resultset_STAR_ invokeStatic jdbc.clj 1084]
  [$db_query_with_resultset_STAR_ invoke jdbc.clj 1065]
  [$query invokeStatic jdbc.clj 1155]
  [$query invoke jdbc.clj 1117]
  [$query invokeStatic jdbc.clj 1133]
  [$query invoke jdbc.clj 1117]
  [montaj.database.logic$find_book_data invokeStatic logic.clj 7]
  [montaj.database.logic$find_book_data invoke logic.clj 5]
  [montaj.commands.list$list_books invokeStatic list.clj 11]
  [montaj.commands.list$list_books invoke list.clj 5]
  [cli_matic.core$invoke_subcmd invokeStatic core.clj 797]
  [cli_matic.core$invoke_subcmd invoke core.clj 785]
  [cli_matic.core$run_cmd_STAR_ invokeStatic core.clj 831]
  [cli_matic.core$run_cmd_STAR_ invoke core.clj 817]
  [cli_matic.core$run_cmd invokeStatic core.clj 841]
  [cli_matic.core$run_cmd invoke core.clj 833]
  [montaj.core$_main invokeStatic core.clj 18]
  [montaj.core$_main doInvoke core.clj 16]
  [clojure.lang.RestFn applyTo 137]
  [montaj.core main nil -1]
  [ run 164]]}