In Clojure 1.4 what is the use of refer within require? - clojure

What advantage does using :refer in :require have over using :only in :use? Are the following synonymous?
(ns so.example (:use [my.lib :only [function]]))
and
(ns so.example (:require [my.lib :refer [function]]))

Main idea of adding :refer to :require is to get rid completely of :use, leaving only one operator to load other packages. You can emulate existing :use with (:require [my.lib :refer :all])...

yes, they are equivalent,
:refer and :require are the basic operations required to build namespaces. :use is more convienient
:require causes classes to be loaded
:refer adds things to the name space which is really just a map (actually a couple of maps)
:use is :refer + :require
as much is it may look like it, there really is no magic to namespaces
if you make a namespace like this
(ns so.example (:use my.lib))
the equivalent with :require would be:
(ns so.example (:require [my.lib :refer [function1 function2 function3
list every function in example
here and remember to keep it
up to date ]]))

As of the 1.4.0 release, there's no longer a good reason to use use. Use require :refer instead. From the Clojure 1.4.0 changelog: "require can now take a :refer option. :refer takes a list of symbols to refer from the namespace or :all to bring in all public vars."
(from https://8thlight.com/blog/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html)

Related

What is the difference between core.clj and inope.clj in a clojure project?

What is the difference between core & inope?
I have a very brief idea that core is like the main equivalent in Java. And inope is like an interface between java and clojure, although I dont understand the purpose of inope entirely.
I found this in a project and this is my understanding:
inope.clj is used for writing java clojure interoperable functions.
The namespace contents imply that it functions like core.clj here.
in this inope.clj file, they have imported dependencies and defined java-clojure interoperable functions in gen-class as such :
(ns prject-avon.inope
(:require [prject-avon.ioutil :as utl]
[aero.core :as aero-core :refer (read-config)]
[clojure.java.data :as clj-data]
[malli.core :as m]
[malli.util :as mu]
[malli.instrument :as mi]
[malli.error :as me]
[malli.json-schema :as json-schema]
(:gen-class
:methods [ ^{:static true} [validateData [Object String] Boolean]
]))
<Functions are defined here>
Those are just names, there's no significance to them. In particular, I've never heard of inope myself. The only way you can reliably judge is by the namespace's contents and their usage. It's also very possible that a single namespace contains all sorts of unrelated stuff.

Using Incanter and Clojure Soup together

I am learning Clojure - it's a lot of fun! I am trying to use Incanter and Clojure Soup in the same file:
(require '[jsoup.soup :as soup])
(use '(incanter core stats io charts datasets))
And I get the following error:
CompilerException java.lang.IllegalStateException: $ already refers to: #'jsoup.soup/$ in namespace: user, compiling
I think I understand why, but how can I solve this problem? Appreciate this website and all the gurus on it!
Thanks.
If you only actually use one of the $ functions then you can exclude the other one
(ns myproject.example
(:require [jsoup.soup :as soup]
[incanter [core :refer :all :exclude [$]]
[stats :refer :all]
[io :refer :all]
[charts :refer :all]
[datasets :refer :all]]))
or you can take the approach of explicitly naming the vars you want to refer to in your namespace and explicitly calling the others by namespace-alias/function, which would look more like this:
(ns myproject.example
(:require [jsoup.soup :as soup]
[incanter [core :refer [$ ... and others here ...]
:as incanter]
[stats :as stats]
[io :as io]
[charts :as charts]
[datasets :as dataset]]))
The use method of using other namespaces is discouraged in modern clojure code and has been subsumed by the refer form, so I use that form in these examples. It's also strongly encouraged to put the refer forms in the namespace declaration.

Provide multiple implementations for a Clojure protocol

I have a namespace that exposes common data-related functions (get-images, insert-user). I then have two database backends that have those same functions and implement them differently. They implement the interface as it were. Each backend is contained within a namespace.
I can't seem to be able to find a good solution on how to accomplish this.
I tried dynamically loading the ns but no luck. Once you do (:require [abc :as x]), the x isn't a real value.
I tried using defprotocol and deftype but that's all kinds of weird because the functions in the deftype need to be imported, too and that messes everything up for me.
Is there some idiomatic solution to this?
I don't see why protocols are not sufficient?
In ns data.api:
(ns data.api)
(defprotocol DB
(get-images [this])
(insert-user [this]))
In ns data.impl1:
(ns data.impl1
(:require [data.api :refer :all]))
(defrecord Database1 [connection-params]
DB
(get-images [_] ...)
(insert-user [_] ...))
Same thing in ns data.impl2.
Then when you go to use a particular db, just create the correct record:
(ns data.user
(:require [data.api :refer :all])
[data.impl1 :refer (->Database1)])
(defn use-db []
(let [db1 (->Database1 {})]
(get-images db1)))

using clojure.string causes WARNINGs

When using clojure.string, I receive the following warnings
WARNING: replace already refers to: #'clojure.core/replace in namespace: tutorial.regexp, being replaced by: #'clojure.string/replace
WARNING: reverse already refers to: #'clojure.core/reverse in namespace: tutorial.regexp, being replaced by: #'clojure.string/reverse
my clojure script is:
(ns play-with-it
(:use [clojure.string]))
Is there any way to fix those warnings?
Yes, switch to
(ns play-with-it
(:require [clojure.string :as string]))
and then say e.g.
(string/replace ...)
to call clojure.string's replace function.
With :use, you bring in all Vars from clojure.string directly into your namespace, and since some of those have names clashing with Vars in clojure.core, you get the warning. Then you'd have to say clojure.core/replace to get at what's usually simply called replace.
The clash of names is by design; clojure.string is meant to be required with an alias like this. str and string are the most frequently chosen aliases.
In addition to Michał's answer, you can exclude vars from clojure.core:
user=> (ns foo)
nil
foo=> (defn map [])
WARNING: map already refers to: #'clojure.core/map in namespace: foo, being replaced by: #'foo/map
#'foo/map
foo=> (ns bar
(:refer-clojure :exclude [map]))
nil
bar=> (defn map [])
#'bar/map
In addition to Alex's answer you can also refer only the vars you want from a given namespace.
(ns foo.core
(:use [clojure.string :only (replace-first)]))
This would not throw a warning since replace-first is not in clojure.core. However, you would still receive a warning if you did the following:
(ns foo.core
(:use [clojure.string :only (replace)]))
In general it seems people are tending toward (ns foo.bar (:require [foo.bar :as baz])).
Since Clojure 1.4 you can refer the individual functions you need from a namespace using :require with a :refer:
(ns play-with-it
(:require [clojure.string :refer [replace-first]]))
This is now recommended over :use.
Assuming you don't need the clojure.string/replace or clojure.string/reverse, that would also remove the warnings.
See this SO question and this JIRA issue for more details.

What's idiomatic clojure for :use

I've seen several different ways for :use in clojure--what's the idiomatic/preferred method?
#1
(ns namespace.core
(:use [[something.core]
[another.core]]))
or #2 EDIT: Use this with conjunction with :only.
(ns namespace.core
(:use [something.core]
[another.core]))
or #3
(ns namespace.core
(:use [something.core
another.core]))
or #4
(ns namespace.core
(:use (something.core
another.core)))
or #5 EDIT: This is idiomatic, but one should be using :use as in #2
(ns namespace.core
(:use something.core
another.core))
Choice #5 is idiomatic, unless you are passing additional options such as :only, :exclude, etc. Colin's blog post covers the options in great detail.
The API for dealing with namespaces is unnecessarily difficult to learn. However, it is certainly capable enough for a wide variety of uses, so the pressure for a rewrite has yet to reach the boiling point for anyone.
Actually none of them are idiomatic. You should always have an :only clause in your :uses. Your best bet is adding :only to #2. If you don't want to enumerate all the vars you're taking from another namespace, consider (:require [foo.bar :as bar]).
One point of note that we should mention is that the
(:use (clojure set xml)) statement is considered a promiscuous operation
and therefore discouraged. [...] When organizing your
code along namespaces, it’s good practice to export and import only those
elements needed.
-from the Joy of Clojure, page 183.
The one exception is that a test namespace should bare-use the namespace it tests.
The cases 1, 3 and 4 are not valid and throw some Exception. I haven't seen 2 - only in combination with :only or the like.
(ns namespace.core
(:use
[something.core :only (x)]
another.core))
I usually use 5.
In Clojure 1.4+ I wouldn't use use at all. require can do all that use can do now, so forget about use. One less thing to worry about.
If you want use-like behaviour (still bad form, imo) you can do:
(ns namespace.core
(:require
[something.core :refer :all]
[another.core :refer :all]))
If you want :use .. :only behaviour, use:
(ns namespace.core
(:require
[something.core :refer [foo bar]]
[another.core :refer [quux]]))
More detail: In Clojure 1.4 what is the use of refer within require?