Monthly Archives: June 2014

The less-familiar parts of Lisp for beginners — signal

Our review of obscure Lisp features for newcomers arriving from C++ now comes to signal.  Some time ago I wrote a series of articles about exception handling in Lisp from a C++ perspective, you might want to review that series here.

As discussed in the earlier series, signal behaves somewhat like a C++ throw, but with some important differences.  Foremost among them is that if there is no handler for the signaled condition, the signal form returns nil and execution continues at the next statement.  This is unlike C++, where an unhandled exception causes an immediate ABEND.

The less-familiar parts of Lisp for beginners — shiftf

Continuing through obscure Lisp commands, we arrive at the shiftf macro.  This is very similar to the rotatef macro that we described earlier.  The difference is that the first place, rather than rotating to the last place as in rotatef, is removed and a new programmer-supplied value is inserted into the last place.  The dropped value is returned.  Here are some examples:
*slime-repl sbcl*

CL-USER> (let ((one 1)
               (two 2)
               (three 3))
           (rotatef one two three)
           (format t
                   "After rotatef, one= ~D  two= ~D  three= ~D~%"
                   one two three))
After rotatef, one= 2  two= 3  three= 1
NIL
CL-USER> (let ((one 1)
               (two 2)
               (three 3))
           (shiftf one two three 10)
           (format t
                   "After shiftf, one= ~D  two= ~D  three= ~D~%"
                   one two three))
After shiftf, one= 2  two= 3  three= 10
NIL
CL-USER> (let ((mylist (list 1 2 3 4 5)))
           (rotatef (first mylist)
                    (second mylist)
                    (third mylist))
           (format t "After rotatef, mylist= ~A~%" mylist))
After rotatef, mylist= (2 3 1 4 5)
NIL
CL-USER> (let ((mylist (list 1 2 3 4 5)))
           (shiftf (first mylist)
                   (second mylist)
                   (third mylist)
                   10)
           (format t "After shiftf, mylist= ~A~%" mylist))
After shiftf, mylist= (2 3 10 4 5)
NIL

Brief observations on travel in Bulgaria

Chin Yi and I recently returned from a vacation to Bulgaria and Romania.  Here are my very brief thoughts and advice to others who plan a similar journey in Bulgaria.

Language: Between us, we have conversational ability in English, French, Japanese, and two dialects of Chinese.  Also some limited capacity in German.  We had no Bulgarian to speak of.  In practice, this meant that we had to try to communicate in English.  In Bulgarian hotels you can usually find somebody who speaks English (though we did end up using German a lot at one hotel, for lack of another common language), but elsewhere, talking to a taxi driver or a bus ticket agent, you may find that English doesn’t get the message across, particularly in the smaller cities.  I loaded the Google Translate app onto my cell phone and installed the Bulgarian language package for offline use, which helped immensely in these situations.  Learn to pronounce the Cyrillic letters used in Bulgaria, it will help you to read signs on buses and addresses.

Cell phone: Before we went, I did some research to find how to get phone and Internet service on our Android phones.  I decided to use the Globul carrier, based on what I could find on their English-language website.  This wasn’t very successful.  While the phone and text-messaging were cheap to set up, I never got Internet going because, as one representative later told me, “the English website is out of date, we no longer offer pre-paid Internet”.  Our phones started with about 3 Bulgarian Lev in air time credit, and we burned that quickly on a couple of phone calls and a dozen text messages.  If I were to plan a return trip to Bulgaria, I wouldn’t be using Globul, but I’d have to do more research to find out what my alternatives might be.

Hotels: As I noted, most hotels had some English-speaking staff, except in the smaller cities.  In those hotels where we stayed more than one night, housekeeping didn’t come.  You might have to request it, or put out a sign.  Breakfast was pretty standard, breads, cheese, meats, eggs and omelets, fruit juice, and tea or coffee.  Sometimes included in the room price, sometimes charged extra.

Laundry: This was a bit of a shock for us.  Coin laundries are rare in Bulgaria, there might be a few in some of the bigger cities, but don’t expect to be able to find one.  Some dry-cleaners will do laundry by the kilogram, we eventually found a place in Varna that would do it for us, 12 Bulgarian Lev for rush service of about 5 days of clothing for two people.  Hotels may have a next-day service to send out to a cleaner for by-the-kilogram laundry, but they may not, and this doesn’t help when you’re only staying one night.

Restaurants: The restaurants are officially non-smoking indoors, though sometimes that didn’t turn out to be the case.  Best to check, if smoke is a problem for you.  Also, while we were there, the restaurants seemed to have about a 50% failure rate on their credit-card equipment, so even if you see a credit card sign on the door, ask when you go in to make sure they can process your payment, or make sure you have enough cash on hand.  The cuisine in Bulgaria is reminiscent of Greece and Turkey.  You’ll find shawarma and shish houses, and lots of offerings of roasted and grilled meat and fish.  One staple of restaurants seems to be the “shopska salad”.  It’s what I would call a Greek salad.  Tomatoes, cucumbers, bell peppers, olives, onions, feta cheese, spices, and oil.  No lettuce.  If you have trouble communicating with your waiter, you can be pretty sure he’ll understand a request for “shopska”, and will be able to bring one to you.  Even in restaurants where we couldn’t communicate the concept of “water”, we were able to get a shopska salad.

Inter-city travel: The geography of Bulgaria is a bit unfriendly to trains.  There is a mountain range that runs West to East from Sofia, effectively preventing North-South rail infrastructure.  We went from city to city by bus.  Buses are non-smoking, may be air-conditioned, and will occasionally have on-board washroom facilities for the more heavily-traveled routes.  Bus travel is very inexpensive.  I would say there’s no reason to buy a Eurail pass for travel within Bulgaria, it’s unlikely to be helpful.  If I were doing the same trip again, I’d be tempted to get an international driver’s license and rent a car.

Things to see: Really, this depends on the traveler, you’ll have to choose those yourself.  We went to Sofia, to Rila Monastery, Plovdiv, the rose festival in Kazanluk, and Golden Sands near Varna.

The less-familiar parts of Lisp for beginners — shared-initialize

We’ll now describe, briefly, the standard generic function shared-initialize.  The way this function is interesting to the programmer is very much like that of initialize-instance, so the reader might want to review that earlier article.  In that article, I discussed how initialize-instance is called within make-instance, and by specializing an :after method on initialize-instance, it is possible to write additional code similar to what a C++ programmer would think of as the body of a constructor.  Where initialize-instance fills in the slots, like the initialization list in a constructor, the :after method on it allows the programmer to do other things than just fill in member slots.

Since that article appeared, though, we’ve talked about other ways that an object can be made.  We saw reinitialize-instance, and make-instances-obsolete, the latter as a prelude to update-instance-for-redefined-class, which we have not yet discussed.  These two cases, which do not correspond to any obvious C++ equivalent, do not call initialize-instance, so the programmer’s :after method won’t be called if they are used.

This is where shared-initialize enters the picture.  The shared-initialize generic function is called by initialize-instance, and also by reinitialize-instance, update-instance-for-redefined-class, and update-instance-for-different-class.  That means that by specializing an :after method on shared-initialize, just the way we did it earlier for initialize-instance, we can write code that will be executed whenever the new object is created by any of these routes.  Naturally, if the code should do different things for these different cases, you’ll want to specialize on the outer methods, but if they all have to run the same code, shared-initialize covers all the cases at once.

The less-familiar parts of Lisp for beginners — shadowing-import

Now, we discuss shadowing-import.  We skipped over import earlier, as it seemed fairly simple, but shadowing-import is interesting in the way it differs from import, so we’ll talk about it a bit now.

The import function allows a symbol from one package to be visible in another.  Note, however, that if a symbol by that name already exists in the package into which the symbol is being imported, an error condition is raised.  To avoid the error, you first have to unintern the existing symbol in the package before importing the symbol from the other package.

The shadowing-import function works like import, but shadows any existing symbol rather than raising an error condition.  The imported symbol replaces the formerly-existing one.

Here is a transcript of that behaviour.  Note that import fails with an error, while shadowing-import succeeds:
*slime-repl sbcl*

CL-USER> (make-package 'foreign)
#<PACKAGE "FOREIGN">
CL-USER> (intern "MY-SYMBOL" 'foreign)
FOREIGN::MY-SYMBOL
NIL
CL-USER> (intern "MY-SYMBOL")
MY-SYMBOL
NIL
CL-USER> (import 'foreign::MY-SYMBOL)
; Evaluation aborted on #<NAME-CONFLICT {1002FD4373}>.
CL-USER> (shadowing-import 'foreign::MY-SYMBOL)
T