Cling a C++11 interpreter
Posted on August 14, 2012 by Sol

A C++11 REPL may sound strange, after all C++ is generally seen as a compiled language. However, any programming language can be implemented as a compiler or as an interpreter and Cling happens to be an interactive C++ interpreter based on LLVM and Clang.

If you’ve ever programmed in a language that can be used in a Read-eval-print-loop or REPL you already know what productivity boost can be to be able to test an idea without waiting for your build system to compile your code. Even with tools like make you need sometimes to wait from a few seconds to a few minutes just to see the effects of some small change in a particular piece of code.

Cling lets you test a C++ piece of code in the same way you would do it in a language like Lisp, Ruby or Python, or almost the same …

Let’s try a trivial C++ example - create an integer and add a constant to this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Sols:~ sol$ cling -std=c++11

****************** CLING ******************
* Type C++ code and press enter to run it *
*             Type .q to exit             *
*******************************************
[cling]$ 
[cling]$ int a = 10
(int) 10
[cling]$ a + 10
(int const) 20
[cling]$ 

Using C++ like a calculator is not particularly fun, what about creating a lambda expression ? Assuming you’ve started the interpreter with the -std=c++11 option we can write directly:

1
2
3
[cling]$ int x = [](int a,int b) -> int { return a + b; }(2,4)
(int) 6
[cling]$ 

Or, even better let’s store our lambda expression in a variable using auto:

1
2
3
4
5
6
7
[cling]$ auto func = [](int a, int b) -> int { return a+b; };
[cling]$ 
[cling]$ func(2, 3)
(int const) 5
[cling]$ func(2, 4)
(int const) 6
[cling]$ 

See the pattern ? I can test a C++11 snippet directly, without the need to actually create a file, include any header file or even without explicitly printing the result and all this by writing a single line of code.

Cling also lets you write your code in a separate file and load this at the interpreter’s prompt, say that you have a C++ function saved in func.cpp and you want to load this:

1
2
3
void test() {
	std::cout << "just a test" << std::endl;
}

and the interpreter usage:

1
2
3
4
5
[cling]$ #include <iostream>
[cling]$ .L func.cpp
[cling]$ test()
just a test
[cling]$ 

Please note the use of .L file_name.cpp, Cling defines a few commands that starts with a dot like:

  • .L - for loading a file or a library.
  • .rawInput - toggle on/off raw input.
  • .q - for closing the interpreter.

Can you define a function in the REPL ? Sure, however, at the time of this writing, Cling require that you toggle the raw input when you define a function in the REPL:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
cling]$ .rawInput
Using raw input
[cling]! void test2() {
[cling]! ?   std::cout << "this was defined in the REPL" << std::endl;
[cling]! ?   }
[cling]! .rawInput
Not using raw input
[cling]$ test2()
this was defined in the REPL
[cling]$ 

You can also create a class in the REPL:

1
2
3
4
5
6
7
[cling]$ class Foo {
[cling]$ ?   int state;
[cling]$ ?   public:
[cling]$ ?   Foo();
[cling]$ ?   int get_state();
[cling]$ ?   };
[cling]$ 

For actually implementing the member functions you will need to toggle raw input again:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[cling]$ .rawInput
Using raw input
[cling]! Foo::Foo() {
[cling]! ?   state = 1;
[cling]! ?   }
[cling]! int Foo::get_state() {
[cling]! ?   return state;
[cling]! ?   }
[cling]! .rawInput
Not using raw input

Now, we can use the above class:

1
2
3
4
5
[cling]$ Foo tp
(class Foo) @0x1014d6054
[cling]$ tp.get_state()
(int const) 1
[cling]$ 

What about extending Foo with a new method ? If you try to redefine Foo in Cling you will get an error. You could derive a class from Foo if you need. However, because our initial implementation of Foo uses a private variable state you won’t be able to extend this in a meaningful way. Also, at the time of this writing, Cling seems to not be able to let you unload an existing class, function or variable definition.

Observation: If your class is written in an external file you don’t need to use the raw input command, you will need however to load the class definition and implementation.

If you want to build Cling on your machine you could read the instructions from Cling’s website. I’ve build this on a Mac computer, assuming you have the Command Line Tools from Apple installed this is a resume of how I build Cling:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cd ~
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
svn co http://root.cern.ch/svn/root/trunk/interpreter/cling/
cd ..
cd projects
svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
cd ..
cat tools/cling/patches/*.diff | patch -p0
cd ~
mkdir build && cd build
../llvm/configure --prefix=/usr/cling --enable-optimized --enable-targets=host
make -j 2
sudo make install

Now, when you want to use Cling you could add it to your path with:

1
export PATH=/usr/cling/bin:$PATH

I don’t recommend permanently adding Cling to your path because /usr/cling/bin contains a non-Apple Cland and LLVM.

If you are interested in learning more about the new C++11 syntax I would recommend reading Professional C++ by M. Gregoire, N. A. Solter, S. J. Kleper 2nd edition:

or, if you are a C++ beginner you could read C++ Primer (5th Edition) by S. B. Lippman, J. Lajoie, B. E. Moo.

blog comments powered by Disqus