Fundamentally different REPL behavior depending upon namespace?

I am once again making a pass at learning Clojure, and currently I am going through a Pedestal tutorial. Along the way, I look up Clojure language features that I don’t know, and I test them in the REPL.

In my Pedestal learning REPL I am in “pedrepl.server” namespace. But I am unable to test basic things like hashmap destructuring. In an unrelated, default REPL, it works as per the documentation:

pedrepl.server=> h
{:a 1, :b 2, :c 3}
pedrepl.server=> (let [{:keys [a c]} h] (println a c))
nil nil
nil

vs

user=> h
{:a 1, :b 2, :c 3}
user=> (let [{:keys [a c]} h] (println a c))
1 3
nil

Why is this core behavior different?

1 Like

Hum… can you explain what that pedestal REPL is? How do you start it?

Right now I can only think of two things… Maybe your pedestal REPL is using a really old version of Clojure that didn’t support the :keys destructuring shortcut? Or maybe in your pedestal REPL you didn’t refer clojure.core, for example if you created the namespace with in-ns and so destructuring is missing from the namespace?

I was following this Pedestal REPL development tutorial: http://pedestal.io/guides/developing-at-the-repl , and I started my repl with lein repl. Everything in the tutorial worked as it should, but when I tried to play with destructuring, that obviously didn’t work as it should.

In the working example, I just went to a directory with no project.clj and ran lein repl.

Hello, @z9znz! Welcome to ClojureVerse.

My two cents: It looks like something weird happened in the creation of the pedrepl.server namespace.

Here’s a REPL session where I tried to reproduce some of the same behavior. I don’t get your weird let behavior, though – I just get a namespace where let doesn’t work. Perhaps you can look into how your namespace gets created? Perhaps try to import clojure.core explicitly, like I have to do below?

Here is a simple and an advanced guide to using namespaces at the REPL if you want some reading material.

Good luck!

Teodor

user> (def h {:a 1 :b 2 :c 3})
#'user/h
user> h
{:a 1, :b 2, :c 3}
user> (let [{:keys [a c]} h]
        (println a c))
1 3
nil
user> (in-ns 'my.ns)
#namespace[my.ns]
my.ns> ;; my.ns is a fresh one
my.ns> h
Syntax error compiling at (api:localhost:43183(clj)*:1:8362).
Unable to resolve symbol: h in this context
my.ns> (def h {:a 1 :b 2 :c 3})
#'my.ns/h
my.ns> h
{:a 1, :b 2, :c 3}
my.ns> (let [{:keys [a c]} h]
        (println a c))
Syntax error compiling at (api:localhost:43183(clj)*:30:8).
Unable to resolve symbol: let in this context
my.ns> (require '[clojure.core :refer [let]])
Syntax error compiling at (api:localhost:43183(clj)*:34:8).
Unable to resolve symbol: require in this context
my.ns> recur
Syntax error compiling at (api:localhost:43183(clj)*:1:8362).
Unable to resolve symbol: recur in this context
my.ns> (in-ns 'user)
#namespace[user]
user> (ns-publics 'my.ns)
{h #'my.ns/h}
user> (-> (ns-publics 'my.ns) (get 'h))
#'my.ns/h
user> (-> (ns-publics 'my.ns) (get 'h) deref)
{:a 1, :b 2, :c 3}
user> ;; this time, create it with the ns macro to ensure that we get clojure.core in there
user> (ns my.ns)
nil
my.ns> (ns-publics)
Execution error (ArityException) at my.ns/eval27956 (form-init18142885465825919170.clj:51).
Wrong number of args (0) passed to: clojure.core/ns-publics
my.ns> (ns-publics *ns*)
{h #'my.ns/h}
my.ns> recur
Syntax error compiling at (api:localhost:43183(clj)*:1:8362).
Unable to resolve symbol: recur in this context
my.ns> (in-ns 'user)
#namespace[user]
user> ;; Oops, that didn't work. I think ns just switches to the namespace if it already exists.
user> ;; Let's require `clojure.core` explicitly this time.
user> (ns my.ns 
        (:require [clojure.core :refer :all]))
nil
my.ns> (ns-publics *ns*)
{h #'my.ns/h}
my.ns> require
#function[clojure.core/require]
my.ns> ;; There we go. Now I have a working, normal namespace, and I've got access to Clojure.core
my.ns> (let [{:keys [a c]} h]
        (println a c))
1 3
nil
my.ns> ;; Now it works!

1 Like

Now I can’t reproduce the behavior. The two repls from my original post are closed, and I was unable to recreate the scenario that fails.

For the most part, the state of the pedestal repl was based on the commands suggested in the tutorial that I linked. There were also several calls to (clojure.tools.namespace.repl/refresh) to reload changed sources.

Since I was able to use let without an error, I assume that clojure.core was already visible.

In any case, thanks for everyone’s attention. I’ll look at the namespace links, but my original situation will remain a mystery I guess.

Sounds good! Glad you got it working!

For the record, I’ve gotten into super-weird REPL states myself. Clojure does give you the tools to possibly break anything you touch. Which has effects that are totally awesome, but you can cut yourself. I restart the REPL once in a while myself, but it gets rarer as I learn more.