1.2.1 Importing FSet Symbols

There’s yet another choice to make, once you’ve decided to import FSet symbols: do you want all of them, most of them, or just the ones you’re actually using?

If you want the full FSet experience, and you’re starting a new project, the easiest way is to add :fset2 to the :use clause of your defpackage form, as in this example, and copy the :shadowing-import-from clause:

(defpackage :my-package
  (:use :cl :fset2
        :misc-extensions.gmap :misc-extensions.mvlet)  ; explained in next section
  (:shadowing-import-from :fset2
			  ;; Shadowed type/constructor names
			  #:set #:map
			  ;; Shadowed set operations
			  #:union #:intersection #:set-difference #:complement
			  ;; Shadowed sequence operations
			  #:first #:last #:subseq #:reverse #:sort #:stable-sort
			  #:reduce
			  #:find #:find-if #:find-if-not
			  #:count #:count-if #:count-if-not
			  #:position #:position-if #:position-if-not
			  #:remove #:remove-if #:remove-if-not
			  #:substitute #:substitute-if #:substitute-if-not
			  #:some #:every #:notany #:notevery
			  #:search #:mismatch))

However, there’s a downside to :use, leading many people to avoid it. Because it imports all external symbols of the specified packages, it can cause name conflicts with your code. This is especially true if you’re adding FSet to an existing codebase, but even in a new one, there is a possibility that I might add new exports to package fset2 at some point in the future that would cause a conflict. I don’t think the odds of such a conflict are large, but the risk exists: you could upgrade FSet one day and have something break for this reason.

Because of that, the generally recommended approach is to use an :import-from clause instead, to import only the symbols you are using or think you are likely to use — or even the full export list as it stands at the moment. The downside of that is that the list may get quite long; package fset2, as of this writing, exports 339 symbols. Still, you may prefer this approach, to protect yourself against future exports.

The next question is whether you want all the above shadowing-imports, which are shadowing builtin CL symbols. Here is a description of each of these symbols, to help you understand the consequences of importing it and to decide whether you want to.

set

A no-brainer: import fset2:set. The CL set is archaic, deprecated in the ANSI CL spec, and easily replaced with (setf (symbol-value …) …), which is stylistically preferable anyway. fset2:set names both a type and a constructor macro for that type.

map

This one is a little harder, because cl:map has perfectly legitimate uses, though it’s rarer than mapcar. But maps are probably the most important FSet type; not importing fset2:map, which again names both the type and its constructor macro, will make writing idiomatic FSet code less pleasant.

What I do, and recommend, is to import fset2:map, and then use my GMap macro as an even more general replacement for cl:map. If you don’t want to do that, one alternative is to use the implementation-specific types/constructor macros ch-map and wb-map; at least those names are shorter than including the package prefix on fset2:map, and of course they don’t shadow anything from CL.

union, intersection, set-difference

These are generic functions, with methods for lists that invoke the CL builtins. I recommend importing them.

complement

A generic function, with a method for functions that invokes the CL builtin. Rarely used, but you may as well import it anyway.

first, last

These are generic functions that return the first or last element of a sequence, which can be a Lisp sequence or an FSet seq. These differ from the CL builtins in two ways: they work on more types than lists, and last returns the last element of its argument, unlike cl:last, which returns the last cons (the cons whose car is the last element). See Divergences from Common Lisp for further discussion. I recommend importing them, though if you have any existing calls to CL last. you’ll have to either change them to lastcons (which is a better name anyway; FSet exports this) or add an explicit cl: qualifier.

subseq, reverse
sort, stable-sort
reduce
find, find-if, find-if-not
count, count-if, count-if-not
position, position-if, position-if-not
remove, remove-if, remove-if-not
substitute, substitute-if, substitute-if-not
some, every, notany, notevery
search, mismatch

These are now generic functions that accept both CL sequences and FSet seqs, with compatibility methods on CL sequences that simply forward the call to the original CL versions. There is little reason not to prefer these; I recommend importing them.

— Well, there is one minor catch. If your code does (setf (subseq …) …) anywhere, you will need to add an explicit cl: qualifier to the subseq; otherwise the expression will cause a runtime error. FSet does not define a setf expander for fset2:subseq, and it would be unsafe for it to do so, as its behavior as a setf place would not match that of cl:subseq. But this is such a rare usage that you’re unlikely to encounter this problem.

Here are some Lisp sequence operations for which FSet does not export a symbol with the same name. I have omitted mutating operations, for which FSet of course has no equivalent.

elt

The FSet operation (which applies to maps as well as seqs) is lookup; see also The @ Macro.

length

The FSet operation (which applies to all FSet collections, not just seqs) is size.

remove-duplicates, merge

Use FSet sets.