The better way to test your theory would be to implicitly construct a String, wait for any hidden instantiation to get garbage collected and then implicitly instantiate another one...wait, I know how to force the garbage collector to run...
String s1 = "foo";
System.out.println(Integer.toHexString(System.identityHashCode(s1)));
System.gc();
String s2 = "foo";
System.out.println(Integer.toHexString(System.identityHashCode(s2)));
Nope.
41ed8741
41ed8741
If it were constructing an anonymous constant or something, I'd imagine it would go away when the garbage collector is run. In fact, it's unthinkable that something no longer being used wouldn't die when the garbage collector runs. Otherwise it would have to spend the time to check all existing objects in memory for a match. I would think that would be ridiculously inefficient. Java isn't exactly known for being efficient, though.
Of course that doesn't work. Neither string literal actually exists at run-time, so the GC never gets to collect anything. Only the strings themselves exist at run-time. At least as far as I know, in a situation like this, the compiler can see the properties of the string ahead of time and will preallocate the string for you. But the Java compiler is a clever little bastard and it also knows that both strings are exactly the same. So it preallocates one of the string and makes the other point to it, but still keeps note that they are different.
In order for your test to work you would actually have to deallocate s1 and run the garbage collector, then check if the two values are the same.
Anyway, time for som
e tutorials:Talking with a LispChapter 1: (Hello-Parens!)The canonical start to any programming tutorial is a hello-world program. We'll do the same for Common Lisp, but you'll need some extra info to get on your way, so excuse me if I'm a bit talkative.
So how to get the bloody thing to run anyway?Common Lisp isn't quite as popular as languages as Java or C. This means that support in most IDEs relies on third-party plug-ins, such as
Dandelion for Eclipse. However, due to historical reasons, Slime and Emacs like each other very much. Emacs itself is written in a different Lisp dialect, more on that later. First, let's get things up and running.
I assume you're working on Windows. In that case, you can use
Lisp Cabinet. This will set up a preconfigured Emacs with Common Lisp and some other useful plugins.
After loading up the net installer for lisp cabinet, you'll see a screen where you can select what components to install. First tick box is desktop shortcuts, which may be ticked if you prefer them. Then we've got Emacs. Here you can select Emacs 23 or Emacs 24. Emacs 24 is officially still in beta, but it has been for nearly a year now and it's pretty much completely stable. IT also comes with a few useful features that emacs 23 lacks, but most of those can be hacked in after the fact. I'll be using emacs 24, but feel free to chose whatever you like. You may also like the autocomplete plugin, so feel free to tick it.
Next tick box is called Common Lisp. Here we meet a little peculiarity of the Common Lisp world. There's not a single, unifying version of Common Lisp. Instead there are several environments. Compare it to C++, which has the GCC compiler and the Intel compiler among others. Standard, SBCL and Clozure CL will be selected. I'd suggest leaving things like this as any lisp environment does a fine job, both those two generally produce the fastest code (I prefer Clozue Cl for development work as it gives some more info when something breaks, but some libraries work on SBCL exclusively so that's why I generally advise getting them both).
If you want to follow the Clojure tutorials I'll write later, you may also want to tick the Clojure box. I won't mention Racket, which is a Scheme dialect, but feel free to explore it at your own leisure if you want to. If you're using Clojure as well. remember to avoid spaces in the path where you install Lisp Cabinet or things will break
Now, let the installer do it's magic, navigate to the path where you installed everything and fire up Lisp Cabinet.
You'll be greeted with a pretty Emacs window. If you ever used Emacs before, this may look a little different as Lisp Cabinet installs it's own color scheme. This can be changed, but that's outside of the scope of this book.
Is that all we're going to get?Patience, my dear.What we have here is just Emacs, but it's not Common Lisp yet. Common Lisp is similar to languages like Python in the sense that you always have a Common Lisp image running in the background. Any code, be it in the form of a script, a compiled program or code you type in for direct evaluation first goes through this image, which handles all the magic needed to get it to work.
So how to get such an image?
Emacs talks to a running image using Slime, the Superior Lisp Integration Mode for Emacs. Slime provides, among others, code evaluation, error handling and profiling options while autocompletion and parenthesis highlighting are also provided as a courtesy of Emacs and Lisp Cabinet.To get a running Common Lisp image and be able to do anything, we simply tell Emacs to start Slime.Hold the meta-key (called Alt on most keyboards) and press x. I'll refer to such a combination as M-x. Holding meta and pressing G would be M-g, holding control (marked crtl on most keyboards) and pressing X would be C-x et cetera. This is standard Emacs jargon, you'll find it in many other documents as well. (if you type something wrong, you can always hit C-g to quit the input)Now after pressing M-x, you'll see a teal M-x appear in the lowest line of your screen. If you start to type, text will appear after it. Type in slime and hit enter. Blam! You'll see some code flashing past and will quickly be greeted by the following line:; SLIME 2011-10-19
CL-USER>
So what is it we're looking at exactly?This is the so-called REPL: The Read, Evaluate, Print Loop. Here we can type in code,which will be read and evaluated and the result will be printed back. Remember when I said Emacs talks to a running Common Lisp image? We can talk directly to the lisp image via the REPL.So let's do some talking:
CL-USER> "Hello, World!"
"Hello, World!"
CL-USER>
As you can see, typing in "Hello, World!" causes the REPL to respond with "Hello, World!". This is because "Hello, World!" is a string literal, which is read in and evaluates to itself. (On a side note, if you want to copy and paste stuff to and from Emacs, you might want to go to options and set 'Use CUA keys'. This makes C-c, C-v and C-x work as expected). So ok, we've got our Common Lisp image to print "Hello, World!", but have we programmed anything? Well, we certainly haven't made any function calls or anything. So let's do that now. We'll call a function that writes "Hello, World!" to the output:
CL-USER> (format t "Hello, World!")
Hello, World!
NIL
CL-USER>
Whoa! What the hell? Why is that format t inside the parenthesis? And where did that nil come from?When I said Common Lisp is a bit different from languages like C, I meant that in more ways then one. First of all, lisp uses so-called S-expresssions. I'll explain then further later on, for now you can remember that they have the following structure:
(<function name> <function argument 1> <function argument 2>.... <function argument n>)
It's essentially a list with in the first spot a function call (or a method or special operator, but we'll cover that later) and the rest arguments to the function call. So in this case, format was the function and t and "Hello, World!" it's arguments. In the case of format, the first value tells it where to print to, the second value is a format string, which is a kind of instruction string that tells it how to print something, and it takes as many further arguments as the format string can handle. So
CL-USER> (format t "~a" "Hello, World!")
Hello, World!
NIL
and
CL-USER> (format t "~a, ~a!" "Hello" "World")
Hello, World!
NIL
CL-USER>
also work, since the ~a tells format: Print out one of your input arguments. The book Practical Common Lisp (Freely available as a
digital version) has a good, but by no means exhaustive chapter on the format function. I'll also cover it if there's popular demand for it.
So about that nil. Let me demonstrate what it is by altering the function call to format a bit again:
CL-USER> (format nil "~a, ~a!" "Hello" "World")
"Hello, World!"
CL-USER>
Now the nil vanished. The reason for this is that if the first argument to format is nil, then instead of printing the output to the standard output (as with t) or a stream (if that stream is the first argument to format), it just returns a string. That is, the string becomes the return value. In the previous cases nil was the return value, indicating that the function was in essence returning nothing of use. nil in Common Lisp is, among others, false, the empty list and the return value of functions that don't have a sensible return value. This is because every function call (and macro call and special operator call) has a return value.
(On a side note, there are other functions besides format that print to the REPL, such as print or prin1 but format is the most versatile, so I'll use that throughout the tutorials)
So now that we've got the REPL to print a string and we've called functions that write output to the REPL, the next canonical step is to make ourself a little function. We'll make a function that takes 1 argument and prints "Hello, <argument>":
CL-USER> (defun hello (input)
(format t "Hello, ~a!" input))
HELLO
CL-USER> (hello "John")
Hello, John!
NIL
CL-USER>
As you can see defining functions is done with defun, which has the following structure:
(defun <function name> (<input argument 1> <input argument 2> .... <input argument n>)
code)
(defun looks like a function call, but it's actually a macro. More on that later)
Also note that we don't have to specify the type of our input, as Common Lisp is dynamically typed. More on that, and the intricacies of defining and using functions later. Lastly, there's that nil again. We haven't specified any output, so where does it come from?
Well, in Common Lisp, you don't need to specify output. By default, the result of evaluating the last expression is used as the return value. An since (format t ...) returns nil, our function also returns nil. Had we used (format nil ...), the result would have been:
CL-USER> (defun hello (input)
(format nil "Hello, ~a!" input))
HELLO
CL-USER> (hello "World!")
"Hello, World!!"
since now the format returns a string, which then gets returned by our own function.
For now we're going to make this into an actual program. The problem is that if we shut down our Common Lisp image, the functions we defined are gone. We don't want that, because that means we have to reprogram everything from scratch again.
While Common Lisp can be developed from the REPL, it's often easier to work with files and only test stuff on the REPL. So let's put our function in a file.
Put the following key combination in Emacs:
C-x f
This is the combination for "find file". This is the general mechanism used for finding existing and new files. Put in the full path of your file, for example c:\Tutorials\Lisp\Hello World.lisp (the .lisp extension is mandatory, else Emacs won't use syntax highlighting) and hit enter. An empty file will appear, but our REPL is gone. Let's fix that first.
Hit C-x 2 or C-x 3 to split the window horizontally or vertically respectively. Select the window where you want the REPL, hit C-b, type in slime-re and hit tab. This will autocomplete to slime-repl-ccl (or slime-repl-sbcl if you only installed that one, but if you have Clozure Common Lisp it should start with it by default) You now have an empty file and the REPL side-by-side. Copy
(defun hello (input)
(format t "Hello, ~a!" input))
(hello "World")
to the file and safe it with C-x s. (if you put the file in a non-existent directory, you'll get an error. Just hit M-x and type make-directory and hit enter twice, then save it again.)
We now have the code in our file, so we can load it whenever we want. With a file open and Slime running, we can always hit C-c C-k to evaluate the whole file. If you do this now, you'll see "Hello, World!" printed to the REPL, as expected. Alternatively, at the REPL, you can hit , (that's the coma key) and type CD to activate change directory, change to where you stored the file then type (load "filename") and it'll do the same thing:
CL-USER> (load "Hello World.lisp")
Hello, World!!
#P"d:/Common Lisp/Tutorial/Lesson 1/Hello World.lisp"
CL-USER>
The return value in this case is a path containing the full name of the file you just loaded.
Just to prove that doing this loads the whole file into the running image, as opposed to just executing it, do the following:
CL-USER> (unintern 'hello)
T
CL-USER> (hello "World!")
; Evaluation aborted on #<CCL::UNDEFINED-FUNCTION-CALL #x187F30F6>.
CL-USER> (load "Hello World.lisp")
Hello, World!!
#P"d:/Common Lisp/Tutorial/Lesson 1/Hello World.lisp"
CL-USER> (hello "World")
Hello, World!
NIL
CL-USER>
The first call to hello will dump you into the error handler since we just removed the function with unintern. Just hit q to exit the error handler. The second call to hello will work, because loading a file makes all functions in that file available in the REPL.
One final note: it's also possible to save compiled code instead of code files, but the functions used to do that differ by lisp implementation. In Clozure Common Lisp it's
save-application and in SBCL it's
save-lisp-and-die. If these pages look like absolute word salad to you, don't despair, I'll handle most if what you need to know at some point. Also, as the name of the SBLC function already indicates, saving an image, as it's called, is going to corrupt the running image to a point where it can't keep on running, so it'll shut itself down once it's done saving.
This concludes the first chapter of my Common Lisp tutorial. Here's a quick recap:- Whenever you use Common Lisp, there's a Common Lisp image running in the background that processes the code
- We use a REPL to talk to the image, I've used the Slime repl for Emacs in this tutorial. A REPL is a Read, Evaluate, Print Loop
- Feeding a literal, such as a string or a number to the REPL will result in it printing that literal
- Common Lisp uses S-expressions, which have the form (<function name> <input arguments>)
- We can output things to the REPL using (format t format-string input-arguments): (format t "Hello, ~a" "World")
- We can define our own functions using (defun <name> (<input arguments>) <code>)
- The result of evaluating the last expression in a function serves as the return value for that function
- We can save code in .lisp files and load the code with the load function or by hitting C-c C-k