diff --git a/pub/CHANGELOG b/pub/CHANGELOG
index 44d660c5260eb0ed37571326038f58febc47836c..50ea6115ab608d2f9a9f9a72fc457efe4cea19d5 100644
--- a/pub/CHANGELOG
+++ b/pub/CHANGELOG
@@ -1,3 +1,7 @@
+
+- New command dv to display list of defined variables
+- Experimental code for 2d plots
+
 Release 2.3.6b of 14mar17:
 
 - Replaced experimental/filesystem by boost/filesystem for compilation under gcc4.8
diff --git a/pub/lib/commands.cpp b/pub/lib/commands.cpp
index 2e9c15ca77fd3214c5d8d61acc3932681d335e3b..5821008a302c94255eb738a2d9b1ad5f876cdaa6 100644
--- a/pub/lib/commands.cpp
+++ b/pub/lib/commands.cpp
@@ -39,6 +39,7 @@
 #include "reduce_spec.hpp"
 #include "rssm.hpp"
 #include "special.hpp"
+#include "variables.hpp"
 
 #include "commands.hpp"
 
@@ -211,28 +212,31 @@ bool frida_command(string cmd)
 
     } else if (cmd == "d") {
         cout << "Directory commands: inspect internal files\n"
-                "  df   list of files\n"
-                "  dz   z-values and spectral ranges\n"
-                "  dp   x|y-values\n"
-                "  dy   y-values\n"
-                "  dr   real parameters\n"
-                "  dc   coordinate names and units\n"
-                "  dd   doc lines\n";
+            "  dc   coordinate names and units\n"
+            "  dd   doc lines\n"
+            "  df   list of files\n"
+            "  dp   x|y-values\n"
+            "  dr   real parameters\n"
+            "  dv   variables\n"
+            "  dy   y-values\n"
+            "  dz   z-values and spectral ranges\n";
 
+    } else if (cmd == "dc") {
+        NEdif::show_coord();
+    } else if (cmd == "dd") {
+        NEdif::show_doc();
     } else if (cmd == "df") {
         NEdif::show_files();
-    } else if (cmd == "dz") {
-        NEdif::show_spectra();
     } else if (cmd == "dp") {
         NOperate::show("xyd");
-    } else if (cmd == "dy") {
-        NOperate::show("y");
     } else if (cmd == "dr") {
         NEdif::show_numpars();
-    } else if (cmd == "dc") {
-        NEdif::show_coord();
-    } else if (cmd == "dd") {
-        NEdif::show_doc();
+    } else if (cmd == "dv") {
+        SVariRegistry::instance()->display_all();
+    } else if (cmd == "dy") {
+        NOperate::show("y");
+    } else if (cmd == "dz") {
+        NEdif::show_spectra();
 
     } else if (cmd == "e") {
         cout << "Edit commands:\n"
diff --git a/pub/lib/variables.cpp b/pub/lib/variables.cpp
index b7d5c761bd42fdc85c6bfb70e5477d3088d91ab6..b9d47a03d717a6d9fd2d81f5c71dc47754fd4cac 100644
--- a/pub/lib/variables.cpp
+++ b/pub/lib/variables.cpp
@@ -7,18 +7,21 @@
 //! \file  variables.cpp
 //! \brief Implements class SVariRegistry.
 
+#include <algorithm>
+
 #include "variables.hpp"
 #include "defs.hpp"
+#include "obj.hpp"
 #include "ptr.hpp"
 
 
-PObj SVariRegistry::find(string key) const
+PObj SVariRegistry::find(const string& key) const
 {
     auto pos = Map.find(key);
     return pos == Map.end() ? nullptr : pos->second;
 }
 
-PObj SVariRegistry::find_or_fail(string key) const
+PObj SVariRegistry::find_or_fail(const string& key) const
 {
     PObj ret = find(key);
     if (!ret)
@@ -27,36 +30,21 @@ PObj SVariRegistry::find_or_fail(string key) const
 }
 
 
-void SVariRegistry::display_functions() const
+void SVariRegistry::display_all() const
 {
-    /*
-    // this implementation works only, if flist is strictly ordered:
-    // first operators by precedence, then functions.
-
-    cout << "Operators by precedence:\n";
-    int precedence = -1;
-    for( int i=0; i<FList.size(); ++i ){
-        const CFunc *f;
-        f = FList[i];
-        if( f->precedence ) { // operators
-            if( f->precedence!=precedence )
-                cout << "\n ";
-            cout << " " << f->key;
-        } else { // functions
-            if( f->precedence!=precedence )
-                cout << "\nBuilt-in functions:\n";
-            cout << "  " << f->key << f->explanation << "\n";
-            }
-        precedence = f->precedence;
-    }
-    */
+    vector<string> keys;
+    for (const auto& it: Map)
+        keys.push_back(it.first);
+    sort(keys.begin(), keys.end());
+    for (const string& key: keys)
+        cout << "  " << key << " = " << Map.at(key)->to_s() << "\n";
 }
 
-void SVariRegistry::register_scalar(string key, PObj val) { Map[key] = val; }
+void SVariRegistry::register_scalar(const string& key, PObj val) { Map[key] = val; }
 
 //! Undefines a key (removes entry from registry); returns true unless the key wasn't defined.
 
-bool SVariRegistry::undef(string key)
+bool SVariRegistry::undef(const string& key)
 {
     auto pos = Map.find(key);
     if (pos == Map.end())
diff --git a/pub/lib/variables.hpp b/pub/lib/variables.hpp
index 96b3a7432c685674df89dc68aaa803660a9f36c1..f80665fd8de36df691fe1c9ee29360bd6167b18f 100644
--- a/pub/lib/variables.hpp
+++ b/pub/lib/variables.hpp
@@ -20,16 +20,16 @@
 class SVariRegistry : public triv::ISingleton<SVariRegistry>
 {
 private:
-    map<string, PObj> Map; //! unsorted hash, for expression evaluation
+    map<const string, PObj> Map; //! unsorted hash, for expression evaluation
 
 public:
-    PObj find(string key) const;
-    PObj find_or_fail(string key) const;
+    PObj find(const string& key) const;
+    PObj find_or_fail(const string& key) const;
 
-    void display_functions() const;
+    void display_all() const;
 
-    void register_scalar(string key, PObj val);
-    bool undef(string key);
+    void register_scalar(const string& key, PObj val);
+    bool undef(const string& key);
 };
 
 #endif // VARIABLES_H