Fork me on GitHub
#beginners
<
2019-01-27
>
Daouda04:01:10

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

andy.fingerhut04:01:30

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

andy.fingerhut04:01:10

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

andy.fingerhut04:01:38

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

Daouda04:01:06

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

Daouda04:01:25

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

andy.fingerhut04:01:50

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)

andy.fingerhut04:01:15

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

Daouda04:01:56

hunnnn i got the same error

Daouda04:01:21

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

Daouda04:01:22

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

Daouda04:01:17

evaluating x# to something else?

Daouda04:01:47

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

Daouda04:01:48

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

hiredman04:01:08

namespace qualified is what it refers to

andy.fingerhut04:01:00

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

hiredman04:01:18

syntax quoting namespace qualifies all the quoted symbols

andy.fingerhut04:01:20

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

Daouda04:01:04

x changed to some weird var name

Daouda04:01:19

yeah they are

hiredman04:01:20

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

hiredman04:01:43

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

hiredman04:01:52

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

hiredman04:01:04

(racket has a lot of really cool facilities for hygienic macros including some really novel stuff around sets of scopes for avoiding symbol capture http://www.cs.utah.edu/~mflatt/scope-sets/)

Daouda04:01:59

thank you guys for your explanations 😄

Daouda04:01:32

i've learnt something more this night 🙂

Santiago09:01:05

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?

temco09:01:16

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.

valtteri09:01:37

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.

andy.fingerhut09:01:24

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.

Santiago09:01:29

ah I get it

andy.fingerhut09:01:35

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.

Santiago09:01:38

thanks guys, that makes sense

Audrius13:01:18

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

orestis14:01:54

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

orestis14:01:53

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

hoopes17:01:22

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?

Chris17:01:23

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

hoopes17:01:09

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

lilactown18:01:39

IME starting with anything is fine

lilactown18:01:01

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

lilactown18:01:15

(for your first project)

TK17:01:13

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

hiredman18:01:36

what makes code production code is it being in production

TK19:01:52

good to know. thanks

didibus18:01:15

@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.

SoV418:01:16

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

SoV418:01:31

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

didibus18:01:47

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

TK19:01:23

great @didibus

sigmaray19:01:12

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 (https://edgeguides.rubyonrails.org/active_record_migrations.html). 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 [clojure.java.jdbc :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.

borkdude19:01:28

@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

borkdude19:01:59

@sigmaray For migrations I use migratus.

borkdude19:01:50

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

orestis20:01:07

@sigmaray if you’re looking for something close to Rails, https://github.com/coast-framework/coast is your closest bet.

flefik20:01:15

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

flefik20:01:37

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

flefik20:01:01

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.

dorab20:01:30

@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. http://www.luminusweb.net/

bartuka23:01:29

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 os.name=Mac and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64

bartuka23:01:22

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

** ERROR: **
JVM Exception: #error {
 :cause No native library is found for os.name=Mac and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64
 :via
 [{:type java.sql.SQLException
   :message Error opening connection
   :at [java.lang.Throwable <init> Throwable.java 265]}
  {:type java.lang.Exception
   :message No native library is found for os.name=Mac and os.arch=x86_64. path=/org/sqlite/native/Mac/x86_64
   :at [java.lang.Throwable <init> Throwable.java 265]}]
 :trace
 [[java.lang.Throwable <init> Throwable.java 265]
  [java.lang.Exception <init> Exception.java 66]
  [org.sqlite.SQLiteJDBCLoader loadSQLiteNativeLibrary SQLiteJDBCLoader.java 333]
  [org.sqlite.SQLiteJDBCLoader initialize SQLiteJDBCLoader.java 64]
  [org.sqlite.core.NativeDB load NativeDB.java 56]
  [org.sqlite.core.CoreConnection open CoreConnection.java 211]
  [org.sqlite.core.CoreConnection <init> CoreConnection.java 76]
  [org.sqlite.jdbc3.JDBC3Connection <init> JDBC3Connection.java 25]
  [org.sqlite.jdbc4.JDBC4Connection <init> JDBC4Connection.java 24]
  [org.sqlite.SQLiteConnection <init> SQLiteConnection.java 45]
  [org.sqlite.JDBC createConnection JDBC.java 114]
  [org.sqlite.JDBC connect JDBC.java 88]
  [java.sql.DriverManager getConnection DriverManager.java 664]
  [java.sql.DriverManager getConnection DriverManager.java 208]
  [clojure.java.jdbc$get_driver_connection invokeStatic jdbc.clj 254]
  [clojure.java.jdbc$get_driver_connection invoke jdbc.clj 233]
  [clojure.java.jdbc$get_connection invokeStatic jdbc.clj 401]
  [clojure.java.jdbc$get_connection invoke jdbc.clj 257]
  [clojure.java.jdbc$db_query_with_resultset_STAR_ invokeStatic jdbc.clj 1084]
  [clojure.java.jdbc$db_query_with_resultset_STAR_ invoke jdbc.clj 1065]
  [clojure.java.jdbc$query invokeStatic jdbc.clj 1155]
  [clojure.java.jdbc$query invoke jdbc.clj 1117]
  [clojure.java.jdbc$query invokeStatic jdbc.clj 1133]
  [clojure.java.jdbc$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 RestFn.java 137]
  [montaj.core main nil -1]
  [com.oracle.svm.core.JavaMainWrapper run JavaMainWrapper.java 164]]}