Sunday, December 14, 2008

Java Resources Support

One of the programming philosophies that I try to follow in order to encourage myself always to do my best work is to assume that every program I write will eventually become a "production" program, distributed to customers all over the world. One detail that falls into that "all over the world" part is internationalization. In other words, I design internationalization into my programs from the start, even when the program is primarily for internal or personal use.

Java makes the string-replacement part of this pretty easy to do with its ResourceBundle class. If you use ResourceBundle consistently, you can easily ship localizations for multiple languages bundled with your application, and other people can take your program and resource files and localize them for other languages without having to recompile your program.

If you have thousands of strings being translated into dozens of languages, you might want to get yourself a sophisticated translation management system or ship around XLIFF files (or perhaps you would like to help write an open source localization repository). But for smaller projects such as I have worked on, I have found that some relatively simple support methods and a bit of convention have served me pretty well.

Contents

Building The Resources

To simplify loading resources, I find it easiest to put them all into one properties file per locale. But to improve maintainability, it is best to keep the resources in multiple files close to the source files in which they are used. I bridge these two conflicting goals by keeping my resources in multiple properties files, then concatenating them all together into a single properties file when I build my application.

To avoid confusion and emphasize the fact that my properties source files are not used in their source file form, I use the extension .props for those files. My concatenation program collects all of the .props files for one locale into one .properties file. I run it once for each locale for which I have files. The concatenation program also adds separators and source filenames in comments between the contents of each source file, and converts non-ascii characters to backslash-u notation. While I am at it, I also stuff some other information into the generated properties files, such as version and date information, so that I can easily access those details at runtime.

In conformance with the standard per-locale naming convention for resource bundle properties files, for each .props base file there can also be locale-specific translations. For example, for the base file Foo.props there could be Foo_hu.props with Hungarian translations, Foo_fr.props with French translations, and Foo_fr_CA.props with French-Canadian translations.

The properties file with the collected resources goes into a file in the same directory as the class files and gets packaged up in the jar file along with the class files. For example, I might name the collected resources file net/jimmc/app/Resources.properties, so it goes in the directory with all of the files in the net.jimmc.app package. When I load it, I specify its location as net.jimmc.app.Resources and the ResourceBundle code automatically finds it from my jar file, as shown in the initResources method below.

The Basic Interface

In order to be able to use the simplest possible code when calling to retrieve resources in my Java apps, I use support code, shown below, to do the following:
  • Encapsulate my ResourceBundle in the support code so that the caller does not need to worry about where the resources come from.
  • Make my resource retrieval functions so that, when a key is not found in the resources, it returns the key as the value of the method rather than throwing an exception. The key then appears in my GUI, where I can see it and correct it later when I want, rather than causing an exception that stops the program and forces me to correct the string immediately before I proceed.
  • Retrieve a resource string and format it with one or more arguments in one call.
In my Java apps, I define a ResourceSource interface with definitions for methods to implement the above functionality:
public interface ResourceSource { /** Get a string from resources. * @param name The resource name. * @return The value of the resource, * or the name if no value is found. */ public String getResourceString(String name); /** Get a string from resources, or null if not found. * @param name The resource name. * @return The value of the resource, * or null if no value is found. */ public String getResourceStringOrNull(String name); /** Get a string from a resource and pass it to MessageFormat.format * with the specified arguments, returning the result. * @param name The resource name. * @param args The args to MessageFormat.format. * @return The formatted resource string. */ public String getResourceFormatted(String name, Object[] args); /** Get a string from a resource and pass it to MessageFormat.format * with the specified one argument put into a new Object[1], * returning the result. * @param name The resource name. * @param arg The argument to MessageFormat.format. * @return The formatted resource string. */ public String getResourceFormatted(String name, Object arg); }

The Basic Implementation

My Application object, a singleton, implements my ResourceSource interface and is the source for resource values for the application. (This is conceptually the same as the IResources interface I mentioned in a previous post.) It contains an internal reference to my resources, so that the caller does not need to worry about that:
import java.text.MessageFormat; import java.util.ResourceBundle; private ResourceBundle resources;
During initialization of my Application object, I call a simple initResources method to load my resources from that one file containing the concatenated contents of all of the props files:
private void initResources() { resources = ResourceBundle.getBundle("net.jimmc.app.Resources"); }
My Application object has a private method that accesses my resources, which all of my other Application resource methods call (to simplify adding other functionality later):
private String getResourceValue(String name) throws MissingResourceException { return resources.getString(name); }
The methods in the Application object that implement the ResourceSource interface all call getResourceValue to get the resource value:
public String getResourceString(String name) { try { return getResourceValue(name); } catch (MissingResourceException ex) { return name; //use the resource name } } public String getResourceStringOrNull(String name) { try { return getResourceValue(name); } catch (MissingResourceException ex) { return null; } } public String getResourceFormatted(String name, Object[] args){ String fmt = getResourceString(name); return MessageFormat.format(fmt,args); } public String getResourceFormatted(String name, Object arg) { String fmt = getResourceString(name); Object[] args = { arg }; return MessageFormat.format(fmt,args); }

Field Names In Format Strings

When using the formatting methods in java.text.MessageFormat you specify the locations of replacement values using numbers in braces, so your formatting string might contain phrases such as {1} or {2,date,medium}. You have to ensure that these index numbers correspond properly to the arguments in the source code that uses that format string. Since these format strings are in a different file (the resource properties file) than the code that uses them, extra care is required to avoid mixing up the numbers, such as when adding or modifying the argument list. To minimize this problem, I add a version of getResourceFormatted that allows using field names rather than numbers in the format strings, so they contain phrases such as {count} and {modtime,date,medium}. When calling these methods, the fieldNames array contains names that correspond to the args of the same index.
/** Get a string from the resource file, map fields names to numbers, * and format it with the given arguments. */ public String getResourceFormatted(String name, Object[] args, String[] fieldNames){ String fmt = getResourceFormat(name,fieldNames); return MessageFormat.format(fmt,args); } /** Get a resource string and map field names to numbers. */ public String getResourceFormat(String name, String[] fieldNames) { String fmt = getResourceString(name); return mapFieldNamesToNumbers(fmt, fieldNames); } /** Replace named MessageFormat field references by field numbers. * The named field reference looks just like a regular format * segment, but with a string in place of the number. */ public String mapFieldNamesToNumbers(String s, String[] fieldNames) { for (int i=0; i<fieldNames.length; i++) { String fieldName = fieldNames[i]; if (fieldName==null || fieldName.equals("")) continue; //skip blanks in the array String p = "\\{"+fieldName+"\\}"; String q = "{"+i+"}"; s = s.replaceAll(p,q); p = "\\{"+fieldName+"\\,"; q = "{"+i+","; s = s.replaceAll(p,q); } return s; }

Runtime Overriding Of Resources

In order to allow loading additional resources at run time, for debugging, I add an additional variable to store my override resources:
private Properties resourceProperties;
I then add a method, which gets called from a debugging command to which I have specified a resources properties file name, to load values from the specified properties file into my override resources:
public void loadResourceProperties(String filename) { if (resourceProperties==null) resourceProperties = new Properties(); try { FileInputStream ifile = new FileInputStream(filename); resourceProperties.load(ifile); String msg = getResourceFormatted("info.LoadedResourceProperties", filename); startupMessage(msg); } catch (Exception ex) { String msg = getResourceFormatted( "error.LoadingResourceProperties",filename); throw new RuntimeException(msg,ex); } }
I modify my private getResourceValue method to look in my override properties before using the regular properties:
private String getResourceValue(String name) throws MissingResourceException { if (resourceProperties!=null) { String v = resourceProperties.getProperty(name); if (v!=null) return v; //found an override property value } return resources.getString(name); }

Recursive Resources

For some applications I want to be able to define resource strings that reference other resource strings or context values provided by the application. The standard replacement text in a message format starts with an open brace followed by a number. In my resource files, after implementing my Field Name extension above, I can also follow an open brace by a field name. With the extension in this section, I can follow an open brace by the "@" character and a context name or the name of another resource. The values for the context names are passed to the formatting methods in a Map.

For example, if I have these resources:
Sample.abc.foo=A formatted string with {@Sample.abc.bar} for {@User} Sample.abc.bar=a nested property
and I create a context Map with User=Jim, then using the methods in this section I can call getResourceFormattedRecurse passing name as "Sample.abc.foo" along with my context and get back "A formatted string with a nested property for Jim".

To implement this capability, I add the following to my ResourceSource interface:
/** Get a string from resources, recursing to do replacement of * special patterns with other resources. */ public String getResourceStringRecurse(String name); /** Get a formatted string from the resource file, including * recursive replacement of special strings. */ public String getResourceFormattedRecurse(String name, Object[] args, String[] fieldNames, Map ctx, int maxRecurse);
I add the corresponding code to my Application object:
public final static int DEFAULT_MAX_RESOURCE_RECURSE = 20; /** Get the value of a resource, replacing the special tags. * @see #replaceResourceRecurse */ public String getResourceStringRecurse(String name) { String value = getResourceStringOrNull(name); if (value==null) return name; return replaceResourceRecurse(value); } /** Get a formatted string from the resource file, including * recursive replacement of special strings. */ public String getResourceFormattedRecurse(String name, Object[] args, String[] fieldNames, Map ctx, int maxRecurse) { String fmt = getResourceString(name); if (maxRecurse>0) fmt = replaceResourceRecurse(fmt, ctx, maxRecurse); if (fieldNames!=null) fmt = mapFieldNamesToNumbers(fmt, fieldNames); return MessageFormat.format(fmt,args); } /** Given a string, look for occurrences of our special replacement * syntax and replace with the referenced value, with a * default recursion limit. * @param s The string through which we look for our special * replacement tags. The replacement tags are of the * form {@XXX} where XXX is the name of the field with * which to replace that tag. * @throws RecursionLimitException if the maximum recursion depth * is exceeded. * @see #replaceResourceRecurse(String,Items,int) */ public String replaceResourceRecurse(String s) { return replaceResourceRecurse(s, null, DEFAULT_MAX_RESOURCE_RECURSE); } /** Given a string, look for occurrences of our special replacement * syntax and replace with the referenced value. * @param s The string through which we look for our special * replacement tags. The replacement tags are of the * form {@XXX} where XXX is the name of the field with * which to replace that tag. * @param ctx The context dictionary for replacement. We first look * for XXX in this dictionary; if not found, we look for * a resource named XXX. May be null. * @param maxRecurse The maximum recursion depth. * @throws RecursionLimitException if the maximum recursion depth * is exceeded. */ public String replaceResourceRecurse(String s, Map ctx, int maxRecurse){ if (s==null) return s; int x = s.indexOf("{@"); //look for our replacements if (x<0) return s; //no replacements StringBuffer sb = new StringBuffer(); int a = 0; while (x>=0 && x<s.length()) { sb.append(s.substring(a,x)); int y = s.indexOf("}",x); if (y<0) { String eMsg = "Missing close brace "+ "in resource after "+ s.substring(x,s.length()); //TBD i18n throw new RuntimeException(eMsg); } String name = s.substring(x+2,y); String v = null; if (ctx!=null) //try the context if we have one v = (String)ctx.get(name); if (v==null) { //If no context property, try resource v = getResourceStringOrNull(name); } if (v!=null) { if (maxRecurse<=0) { throw new RecursionLimitException(name); } //Found the specified resource, recurse on it and //replace specials in it before we plug it into our string. try { v = replaceResourceRecurse(v,ctx,maxRecurse-1); } catch (RecursionLimitException ex) { //If we exceeded the recursion limit, we will be popping //back through here many times; we add on the name of //each item in the recursion chain to add in debugging. ex.setMessage(name+"->"+ex.getMessage()); throw ex; } sb.append(v); } a = y+1; x = s.indexOf("{@",a); } if (a<s.length()) sb.append(s.substring(a)); return sb.toString(); }
RecursionLimitException is a simple exception class that also allows setting the error message:
public class RecursionLimitException extends RuntimeException { private String ourMessage; /** Create a RecursionLimitException. */ public RecursionLimitException(String message) { super(message); } public void setMessage(String msg) { this.ourMessage = msg; } public String getMessage() { if (ourMessage!=null) return ourMessage; else return super.getMessage(); } }

Friday, December 5, 2008

Scala Operator Cheat Sheet

A list of the standard Scala operators.

Contents

Introduction

Scala syntax allows method names to use special characters such as +, * and :, and to use them as infix operators, which effectively allows operator overloading as well as the creation of new operators. This can make code more concise, but can also make it difficult to figure out what a particular Scala operator does, because you can't effectively do a Google search for \: or ++ or ~ or :: or pretty much any Scala operator method name. To make it even more difficult, an implicit conversion may be applied to one of the operands, so the class providing the operator method may not be the same as the declared class of the operand in the source code.

In order to simplify the task of finding Scala operators, I have collected the operator names from the standard Scala classes in this one place. When you are looking for an operator, you can just come to this page and search for the operator within this page using your browser's Find function. You will still need to figure out which of the classes that defines that operator is the right one for your situation, and whether an implicit conversion is being applied.

Of course this page can't list every operator you might find, because Scala allows new operators to be defined in a class. And there is the chance that my list is missing some operators, due either to incomplete or inconsistent documentation of a Scala class, or a bug in my extraction script. But at least it covers most of the standard operators, which should get you further along than having nothing.

Remember that operators that end in : are right associative and the invoking object appears on the right side of the operator. The unary operators + - ! ~ are defined by methods named unary_op where op is one of the four characters; look for those method names at the end of the list.

These operators were extracted from the Scala 2.7.2 final API documentation using the script given below. Many of the methods do not include a summary documentation line, so those appear blank below. Some include a summary that takes more than one line in the source file; my simple little script only picks up the first line. The links point to the on-line API documentation.

Scala Operators

!! AbstractActor
!! Actor Sends msg to this actor and immediately ...
!! Proxy
! Actor Sends msg to this actor (asynchronous).
! Channel Sends a message to this Channel.
! OutputChannel Sends msg to this ...
! Proxy Sends msg to this ...
!= Any o != arg0 is the same as !(o == (arg0)).
!= AnyRef
!= Boolean
!= Byte
!= Char
!= Double
!= Float
!= Int
!= Long
!= Short
!? AbstractActor
!? Actor Sends msg to this actor and awaits reply ...
!? Channel Sends a message to this Channel and ...
!? Proxy
% BigInt Remainder of BigInts
% Byte
% Char
% Double
% Float
% Int
% Long
% Short
% Elem Returns a new element with updated attributes, resolving namespace uris from this element's scope. ...
&&& Parsers.Parser
&& Boolean
&+ NodeBuffer Append given object to this buffer, returns reference on this NodeBuffer ...
& BigInt Bitwise and of BigInts
& Boolean
& Byte
& Char
& Enumeration.Set32 Equivalent to * for bit sets. ...
& Enumeration.Set64 Equivalent to * for bit sets. ...
& Enumeration.SetXX Equivalent to * for bit sets. ...
& Int
& Long
& Short
&~ BigInt Bitwise and-not of BigInts. Returns a BigInt whose value is (this & ~that).
&~ Enumeration.Set32 Equivalent to - for bit sets. ...
&~ Enumeration.Set64 Equivalent to - for bit sets. ...
&~ Enumeration.SetXX Equivalent to - for bit sets. ...
>>> Byte
>>> Char
>>> Int
>>> Long
>>> Short
>> BigInt (Signed) rightshift of BigInt
>> Byte
>> Char
>> Int
>> Long
>> Short
>> Parsers.Parser Returns into(fq)
>> Parsers.Parser Returns into(fq)
> BigDecimal Greater-than comparison of BigDecimals
> BigInt Greater-than comparison of BigInts
> Byte
> Char
> Double
> Float
> Int
> Long
> Ordered
> PartiallyOrdered
> Short
>= BigDecimal Greater-than-or-equals comparison of BigDecimals
>= BigInt Greater-than-or-equals comparison of BigInts
>= Byte
>= Char
>= Double
>= Float
>= Int
>= Long
>= Ordered
>= PartiallyOrdered
>= Short
<< BigInt Leftshift of BigInt
<< Byte
<< Char
<< Int
<< Long
<< Short
<< Buffer Send a message to this scriptable object.
<< BufferProxy Send a message to this scriptable object.
<< Map Send a message to this scriptable object.
<< MapProxy Send a message to this scriptable object.
<< Scriptable Send a message to this scriptable object.
<< Set Send a message to this scriptable object.
<< SetProxy Send a message to this scriptable object.
<< SynchronizedBuffer Send a message to this scriptable object.
<< SynchronizedMap Send a message to this scriptable object.
<< SynchronizedSet Send a message to this scriptable object.
< BigDecimal Less-than of BigDecimals
< BigInt Less-than of BigInts
< Byte
< Char
< Double
< Float
< Int
< Long
< Ordered
< PartiallyOrdered
< Short
< OffsetPosition Compare this position to another, by first comparing their line numbers, ...
< Position Compare this position to another, by first comparing their line numbers, ...
<= BigDecimal Less-than-or-equals comparison of BigDecimals
<= BigInt Less-than-or-equals comparison of BigInts
<= Byte
<= Char
<= Double
<= Float
<= Int
<= Long
<= Ordered
<= PartiallyOrdered
<= Short
<~ Parsers.Parser A parser combinator for sequential composition which keeps only the left result
** Enumeration.SetXX
** Set Intersect. It computes an intersection with set that. ...
** Set This method is an alias for intersect. ...
* BigDecimal Multiplication of BigDecimals
* BigInt Multiplication of BigInts
* Byte
* Char
* Double
* Float
* Int
* Long
* Short
* Set
* RichString return n times the current string
* Parsers.Parser Returns a parser that repeatedly parses what this parser parses, interleaved with the `sep' parser. ...
* Parsers.Parser Returns a parser that repeatedly parses what this parser parses
* Parsers.Parser Returns a parser that repeatedly parses what this parser parses, interleaved with the `sep' parser. ...
* Parsers.Parser Returns a parser that repeatedly parses what this parser parses, interleaved with the `sep' parser.
* Parsers.Parser Returns a parser that repeatedly parses what this parser parses
++: ArrayBuffer Prepends a number of elements provided by an iterable object ...
++: Buffer Prepends a number of elements provided by an iterable object ...
++: BufferProxy Prepends a number of elements provided by an iterable object ...
++: SynchronizedBuffer Prepends a number of elements provided by an iterable object ...
++ Array Returns an array consisting of all elements of this array followed ...
++ Enumeration.SetXX
++ Iterable Appends two iterable objects.
++ IterableProxy Appends two iterable objects.
++ Iterator Returns a new iterator that first yields the elements of this ...
++ List Appends two list objects.
++ RandomAccessSeq Appends two iterable objects.
++ RandomAccessSeqProxy Appends two iterable objects.
++ Seq Appends two iterable objects.
++ SeqProxy Appends two iterable objects.
++ IntMap Add a sequence of key/value pairs to this map.
++ LongMap Add a sequence of key/value pairs to this map.
++ Map Add a sequence of key/value pairs to this map.
++ Set Add all the elements provided by an iterator ...
++ Set Add all the elements provided by an iterator to the set.
++ SortedMap Add a sequence of key/value pairs to this map.
++ SortedSet Add all the elements provided by an iterator ...
++ Stack Push all elements provided by the given iterable object onto ...
++ Stack Push all elements provided by the given iterator object onto ...
++ TreeHashMap
++ TreeHashMap Add a sequence of key/value pairs to this map.
++ Collection Operator shortcut for addAll.
++ Set Operator shortcut for addAll.
++ ArrayBuffer Appends two iterable objects.
++ Buffer Appends a number of elements provided by an iterable object ...
++ Buffer Appends a number of elements provided by an iterator ...
++ Buffer Appends two iterable objects.
++ BufferProxy Appends a number of elements provided by an iterable object ...
++ Map Add a sequence of key/value pairs to this map.
++ MapProxy Add a sequence of key/value pairs to this map.
++ PriorityQueue
++ Set Add all the elements provided by an iterator ...
++ SynchronizedBuffer Appends a number of elements provided by an iterable object ...
++ RichString Appends two iterable objects.
++ RichStringBuilder Appends a number of elements provided by an iterable object ...
++ RichStringBuilder Appends two iterable objects.
++= Map Add a sequence of key/value pairs to this map.
++= MapWrapper Add a sequence of key/value pairs to this map.
++= ArrayBuffer Appends a number of elements in an array
++= ArrayBuffer Appends a number of elements provided by an iterable object ...
++= ArrayStack Pushes all the provided elements onto the stack.
++= Buffer Appends a number of elements in an array
++= Buffer Appends a number of elements provided by an iterable object ...
++= Buffer Appends a number of elements provided by an iterator
++= BufferProxy Appends a number of elements provided by an iterable object ...
++= Map Add a sequence of key/value pairs to this map.
++= MapProxy Add a sequence of key/value pairs to this map.
++= PriorityQueue Adds all elements provided by an Iterable object ...
++= PriorityQueue Adds all elements provided by an iterator into the priority queue.
++= PriorityQueueProxy Adds all elements provided by an Iterable object ...
++= PriorityQueueProxy Adds all elements provided by an iterator into the priority queue.
++= Queue Adds all elements provided by an Iterable object ...
++= Queue Adds all elements provided by an iterator ...
++= QueueProxy Adds all elements provided by an Iterable object ...
++= QueueProxy Adds all elements provided by an iterator ...
++= Set Add all the elements provided by an iterator ...
++= SetProxy Add all the elements provided by an iterator ...
++= Stack Pushes all elements provided by an Iterable object ...
++= Stack Pushes all elements provided by an iterator ...
++= StackProxy Pushes all elements provided by an Iterable object ...
++= StackProxy Pushes all elements provided by an iterator ...
++= SynchronizedBuffer Appends a number of elements provided by an iterable object ...
++= SynchronizedMap Add a sequence of key/value pairs to this map.
++= SynchronizedPriorityQueue Adds all elements provided by an Iterable object ...
++= SynchronizedPriorityQueue Adds all elements provided by an iterator into the priority queue.
++= SynchronizedQueue Adds all elements provided by an Iterable object ...
++= SynchronizedQueue Adds all elements provided by an iterator ...
++= SynchronizedSet Add all the elements provided by an iterator ...
++= SynchronizedStack Pushes all elements provided by an Iterable object ...
++= SynchronizedStack Pushes all elements provided by an iterator ...
++= RichStringBuilder Appends a number of elements provided by an iterable object ...
+: ArrayBuffer Prepends a single element to this buffer and return ...
+: Buffer Prepend a single element to this buffer and return ...
+: BufferProxy Prepend a single element to this buffer and return ...
+: ListBuffer Prepends a single element to this buffer. It takes constant ...
+: ObservableBuffer Prepend a single element to this buffer and return ...
+: SynchronizedBuffer Prepend a single element to this buffer and return ...
+: RichStringBuilder Prepend a single element to this buffer and return ...
+: BufferWrapper Prepend a single element to this buffer and return ...
+: RefBuffer Prepend a single element to this buffer and return ...
+ BigDecimal Addition of BigDecimals
+ BigInt Addition of BigInts
+ Byte
+ Char
+ Double
+ Enumeration.SetXX Create a new set with an additional element.
+ Float
+ Int
+ List
+ Long
+ Short
+ EmptySet Create a new set with an additional element.
+ HashSet Create a new set with an additional element.
+ ListSet.Node This method creates a new set with an additional element.
+ ListSet This method creates a new set with an additional element.
+ Map
+ Map Add a key/value pair to this map.
+ Map Add two or more key/value pairs to this map.
+ Queue Creates a new queue with element added at the end ...
+ Queue Returns a new queue with all all elements provided by ...
+ Set Add two or more elements to this set.
+ Set Create a new set with an additional element.
+ Set1 Create a new set with an additional element.
+ Set2 Create a new set with an additional element.
+ Set3 Create a new set with an additional element.
+ Set4 Create a new set with an additional element.
+ SortedMap Add a key/value pair to this map.
+ SortedMap Add two or more key/value pairs to this map.
+ SortedSet Create a new set with an additional element.
+ Stack Push all elements provided by the given iterable object onto ...
+ Stack Push an element on the stack.
+ TreeSet A new TreeSet with the entry added is returned,
+ Buffer adds "a" from the collection. Useful for chaining.
+ Collection adds "a" from the collection. Useful for chaining.
+ Map Add a key/value pair to this map.
+ Set adds "a" from the collection. Useful for chaining.
+ Buffer Append a single element to this buffer and return ...
+ BufferProxy Append a single element to this buffer and return ...
+ Map Add a key/value pair to this map.
+ Map Add two or more key/value pairs to this map.
+ MapProxy Add a key/value pair to this map.
+ MapProxy Add two or more key/value pairs to this map.
+ ObservableBuffer Append a single element to this buffer and return ...
+ PriorityQueue
+ Set Add a new element to the set.
+ Set Add two or more elements to this set.
+ SynchronizedBuffer Append a single element to this buffer and return ...
+ Parsers.Parser Returns a parser that repeatedly (at least once) parses what this parser parses.
+ Parsers.Parser Returns a parser that repeatedly (at least once) parses what this parser parses.
+= Collection adds "a" from the collection.
+= Map Add a key/value pair to this map.
+= ArrayBuffer Appends a single element to this buffer and returns ...
+= ArrayStack Alias for push.
+= BitSet Sets i-th bit to true. ...
+= Buffer Append a single element to this buffer.
+= BufferProxy Append a single element to this buffer.
+= HashSet Add a new element to the set.
+= ImmutableSetAdaptor Add a new element to the set.
+= JavaSetAdaptor Add a new element to the set.
+= LinkedHashSet Add a new element to the set.
+= ListBuffer Appends a single element to this buffer. It takes constant ...
+= Map Add a key/value pair to this map.
+= Map Add two or more key/value pairs to this map.
+= Map This method defines syntactic sugar for adding or modifying ...
+= MapProxy Add a key/value pair to this map.
+= MapProxy Add two or more key/value pairs to this map.
+= ObservableSet Add a new element to the set.
+= PriorityQueue Add two or more elements to this set.
+= PriorityQueue Inserts a single element into the priority queue.
+= PriorityQueueProxy Inserts a single element into the priority queue.
+= Queue Inserts a single element at the end of the queue.
+= QueueProxy Inserts a single element at the end of the queue.
+= Set Add a new element to the set.
+= Set Add two or more elements to this set.
+= SetProxy Add a new element to the set.
+= Stack Pushes a single element on top of the stack.
+= StackProxy Pushes a single element on top of the stack.
+= SynchronizedBuffer Append a single element to this buffer.
+= SynchronizedMap Add a key/value pair to this map.
+= SynchronizedMap Add two or more key/value pairs to this map.
+= SynchronizedPriorityQueue Inserts a single element into the priority queue.
+= SynchronizedQueue Inserts a single element at the end of the queue.
+= SynchronizedSet Add a new element to the set.
+= SynchronizedStack Pushes a single element on top of the stack.
+= RichStringBuilder Append a single element to this buffer.
+= Reactions Add a reaction.
+= RefBuffer Append a single element to this buffer.
+= CachedFileStorage adds a node, setting this.dirty to true as a side effect
+= IndexedStorage adds a node, setting this.dirty to true as a side effect
+= SetStorage adds a node, setting this.dirty to true as a side effect
-> Map.MapTo
-> Map.MapTo
-- List Computes the difference between this list and the given list ...
-- Map Remove a sequence of keys from this map
-- Set Remove all the elements provided by an iterator ...
-- SortedMap Remove a sequence of keys from this map
-- MutableIterable Operator shortcut for removeAll.
-- Set Operator shortcut for removeAll.
-- Map Remove a sequence of keys from this map
-- MapProxy Remove a sequence of keys from this map
-- Set Remove all the elements provided by an iterator ...
--= Map Remove a sequence of keys from this map
--= MapProxy Remove a sequence of keys from this map
--= Set Remove all the elements provided by an iterator ...
--= SetProxy Remove all the elements provided by an iterator ...
--= SynchronizedMap Remove a sequence of keys from this map
--= SynchronizedSet Remove all the elements provided by an iterator ...
- BigDecimal Subtraction of BigDecimals
- BigInt Subtraction of BigInts
- Byte
- Char
- Double
- Enumeration.SetXX Remove a single element from a set.
- Float
- Int
- List Computes the difference between this list and the given object ...
- Long
- Short
- EmptyMap Remove a key from this map
- EmptySet Remove a single element from a set.
- HashMap Remove a key from this map
- HashSet Remove a single element from a set.
- IntMap Remove a key from this map
- ListMap.Node Creates a new mapping without the given key. ...
- ListMap This creates a new mapping without the given key. ...
- ListSet.Node - can be used to remove a single element from ...
- ListSet - can be used to remove a single element from ...
- LongMap Remove a key from this map
- Map Remove a key from this map
- Map Remove two or more keys from this map
- Map1 Remove a key from this map
- Map2 Remove a key from this map
- Map3 Remove a key from this map
- Map4 Remove a key from this map
- Set Remove a single element from a set.
- Set Remove two or more elements from this set.
- Set1 Remove a single element from a set.
- Set2 Remove a single element from a set.
- Set3 Remove a single element from a set.
- Set4 Remove a single element from a set.
- SortedMap Remove a key from this map
- SortedMap Remove two or more keys from this map
- TreeHashMap Remove a key from this map
- TreeMap Remove a key from this map
- TreeSet Remove a single element from a set.
- UnbalancedTreeMap.Node Remove a key from this map
- UnbalancedTreeMap Remove a key from this map
- Map Remove a key from this map
- MutableIterable
- Set
- ListBuffer Removes a single element from the buffer and return ...
- Map Remove a key from this map
- Map Remove two or more keys from this map
- MapProxy Remove a key from this map
- MapProxy Remove two or more keys from this map
- Set Remove a new element from the set.
- Set Remove two or more elements from this set.
-= Buffer removes "a" from the collection.
-= Collection removes "a" from the collection.
-= Map Remove a key from this map, noop if key is not present.
-= BitSet Clears the i-th bit.
-= Buffer Removes a single element from this buffer, at its first occurrence. ...
-= HashMap Remove a key from this map, noop if key is not present.
-= HashSet Removes a single element from a set.
-= ImmutableMapAdaptor Remove a key from this map, noop if key is not present.
-= ImmutableSetAdaptor Removes a single element from a set.
-= JavaMapAdaptor Remove a key from this map, noop if key is not present.
-= JavaSetAdaptor Removes a single element from a set.
-= LinkedHashMap Remove a key from this map, noop if key is not present.
-= LinkedHashSet Removes a single element from a set.
-= ListBuffer Remove a single element from this buffer. It takes linear time ...
-= Map Remove a key from this map, noop if key is not present.
-= Map Remove two or more keys from this map
-= MapProxy Remove a key from this map, noop if key is not present.
-= MapProxy Remove two or more keys from this map
-= ObservableMap Remove a key from this map, noop if key is not present.
-= ObservableSet Removes a single element from a set.
-= OpenHashMap Remove a key from this map, noop if key is not present.
-= Set Remove two or more elements from this set.
-= Set Removes a single element from a set.
-= SetProxy Removes a single element from a set.
-= SynchronizedMap Remove a key from this map, noop if key is not present.
-= SynchronizedMap Remove two or more keys from this map
-= SynchronizedSet Removes a single element from a set.
-= Reactions Remove the given reaction.
-= CachedFileStorage removes a tree, setting this.dirty to true as a side effect
-= IndexedStorage removes a tree, setting this.dirty to true as a side effect
/% BigInt Returns a pair of two BigInts containing (this / that) and (this % that).
/: Iterable Similar to foldLeft but can be used as ...
/: IterableProxy Similar to foldLeft but can be used as ...
/: Iterator Similar to foldLeft but can be used as ...
/ BigDecimal Division of BigDecimals
/ BigInt Division of BigInts
/ Byte
/ Char
/ Double
/ Float
/ Int
/ Long
/ Short
:/: Document
::: List
:: List
:: Document
:\ Iterable An alias for foldRight. ...
:\ IterableProxy An alias for foldRight. ...
:\ Iterator An alias for foldRight. ...
== Any o == arg0 is the same as o.equals(arg0).
== AnyRef o == arg0 is the same as if (o eq null) arg0 eq null else o.equals(arg0).
== Boolean
== Byte
== Char
== Double
== Float
== Int
== Long
== Short
? Actor Receives the next message from this actor's mailbox.
? Channel Receives the next message from this Channel.
? InputChannel Receives the next message from this Channel.
? Parsers.Parser Returns a parser that optionally parses what this parser parses.
? Parsers.Parser Returns a parser that optionally parses what this parser parses.
\ NodeSeq Projection function. Similar to XPath, use this \ "foo"
\\ NodeSeq projection function. Similar to XPath, use this \\ 'foo
^ BigInt Bitwise exclusive-or of BigInts
^ Boolean
^ Byte
^ Char
^ Int
^ Long
^ Short
^? Parsers.Parser A parser combinator for partial function application
^? Parsers.Parser A parser combinator for partial function application
^^ Parsers.Parser A parser combinator for function application
^^ Parsers.Parser A parser combinator for function application
^^ Parsers.UnitParser A parser combinator for function application
^^^ Parsers.Parser
| BigInt Bitwise or of BigInts
| Boolean
| Byte
| Char
| Enumeration.Set32 Equivalent to ++ for bit sets. Returns a set ...
| Enumeration.Set32 Equivalent to + for bit sets. Returns a set ...
| Enumeration.Set64 Equivalent to ++ for bit sets. Returns a set ...
| Enumeration.Set64 Equivalent to + for bit sets. Returns a set ...
| Enumeration.SetXX Equivalent to ++ for bit sets. Returns a set ...
| Enumeration.SetXX Equivalent to + for bit sets. Returns a set ...
| Int
| Long
| Short
| Parsers.Parser A parser combinator for alternative composition
| Parsers.Parser A parser combinator for alternative composition
| Parsers.UnitParser A parser combinator for alternative composition
|| Boolean
||| Parsers.Parser
||| Parsers.Parser A parser combinator for alternative with longest match composition
||| Parsers.Parser A parser combinator for alternative with longest match composition
||| Parsers.UnitParser A parser combinator for alternative with longest match composition
~! Parsers.Parser A parser combinator for non-back-tracking sequential composition
~! Parsers.Parser A parser combinator for non-back-tracking sequential composition with a unit-parser
~! Parsers.Parser A parser combinator for non-back-tracking sequential composition
~! Parsers.UnitParser A parser combinator for non-back-tracking sequential composition with a unit-parser
~! Parsers.UnitParser A parser combinator for non-back-tracking sequential composition
~> Parsers.Parser A parser combinator for sequential composition which keeps only the right result
~ BigInt Returns the bitwise complement of this BigNum
~ Parsers.OnceParser A parser combinator for sequential composition
~ Parsers.Parser A parser combinator for sequential composition
~ Parsers
~ Parsers.OnceParser A parser combinator for sequential composition with a unit-parser
~ Parsers.OnceParser A parser combinator for sequential composition
~ Parsers.Parser A parser combinator for sequential composition with a unit-parser
~ Parsers.Parser A parser combinator for sequential composition
~ Parsers.UnitOnceParser A parser combinator for sequential composition with a unit-parser
~ Parsers.UnitOnceParser A parser combinator for sequential composition
~ Parsers.UnitParser A parser combinator for sequential composition with a unit-parser
~ Parsers.UnitParser A parser combinator for sequential composition
unary_! Boolean
unary_+ Byte
unary_+ Char
unary_+ Double
unary_+ Float
unary_+ Int
unary_+ Long
unary_+ Short
unary_- BigDecimal Returns a BigDecimal whose value is the negation of this BigDecimal
unary_- BigInt Returns a BigInt whose value is the negation of this BigInt
unary_- Byte
unary_- Char
unary_- Double
unary_- Float
unary_- Int
unary_- Long
unary_- Short
unary_~ Byte
unary_~ Char
unary_~ Int
unary_~ Long
unary_~ Short

Extraction Script

I ran this script under Mac OS X 10.4.11, directed the output to a file, and included that file in this post.
#!/bin/sh - #Extract scala operator names from scaladoc files. #cd to the "api" directory containing the scala API docs, then #run this script and redirect stdout to a file. docsubdir=scala TROOT="http://www.scala-lang.org/docu/files/api" find $docsubdir -name \*.html | \ xargs grep -A 4 'class="signature"' | \ grep -E " <em><a href.*_self|<div>" | \ grep -A 1 -E '<em>.*"_self">([^a-zA-Z0-9_]|unary_)' | \ grep -v '^--' | \ sed -e 's|<em>.*>\(.*\)</a></em>|\1|' | \ sed -e 's/html-/html/' | \ sed -e 's/.*\(<div>.*\)/\1/' | \ uniq | \ awk ' !/<div>/ { if (d!="") { print d; d="" } } {d=d" "$0} ' | \ sed -e 's/^[ ]*//' | \ sed -e 's|\(<div>.*[^>]\)$|\1 ...</div>|' | \ sed -e 's/<div>/<span>/' -e 's|</div>|</span>|' | \ sort +1 | uniq | \ sed -e 's|^\([^ ]*/\)\(.*\).html[ ]*\([^ ]*\)\(.*\)$|<br/><b>\3</b> <a href="'$TROOT'/\1\2.html">\2</a>\4|' | \ grep -v '^<br/><b>[a-tv-zA-Z]' | \ grep -v '[a-zA-Z]\$[a-zA-Z]' | \ sed -e 's/unary_/~~~~unary_/' | sort | sed -e 's/~~~~unary_/unary_/' | \ cat -
Updated 2008-12-21: Added summary line before Contents list.

Tuesday, December 2, 2008

Apology ABCs

I hate making mistakes. But I am human, so I sometimes make them. If I am lucky, my mistakes have no significant impact on anyone else. Inevitably, however, I sometimes make a mistake that adversely affects someone else. In such a situation, I have a simple little ABC mnemonic I use to remind myself of the right things to do. Perhaps you will find them useful some day when you have made a mistake that affects someone else.
  • Apologize for your mistake. Be specific. Don't just say "I am sorry", say something like "I am sorry I broke your table lamp." Mean what you say.

  • Back up the situation to what it was like before your mistake. Undo what was improperly done, right what was wronged, repair what can be repaired, replace what can be replaced.

  • Compensate for what can not be undone. The most obvious compensation is money, but this is not always the most appropriate. Sometimes a little more time or attention is better. Be careful when making compensation. Don't assume you know what would be appropriate compensation without talking to the injured party. You may end up insulting them and making the situation worse. Note that an honest apology will often mean you will be asked for much less in the way of other compensation, or none at all.

  • Desist from doing the same thing again. You may not be able to guarantee you will never make the same mistake again, but you can try to figure out how to change your behavior to minimize that possibility. If you broke the lamp because you were playing frisbee in the living room, don't play frisbee in the living room any more. If you were late for a date or appointment because you got caught up in some other activity and forgot the time, start using an alarm on your watch or phone. Demonstrate that you are trying not to repeat the error.