If you know of good ideas which I don't have listed here, please email them to me at jeske@chat.net [mailto].
OperatingSystems
Security:
VSTa's heirarchial security model - allows you to
create new protection domains 'below' your own,
facilitating things such as sandboxing and
OS supported virus protection. In VSTa, a browser
or mail client can create its own lower kernel-level
protection (i.e. user.jeske.mail). Because this
lower protection level would be made to only have access to
displaying UI and writing files to the mail directory,
your system could not be compromised or infected with
Viruses through that program.
Filesystems:
Netapp's WAFL filesystem. Similar in some ways to
today's journaled filesystems. However, the design
fundamentals, coupled with a small amount of NVRAM
lead to drastically better performance. In WAFL,
no blocks are ever modified in place. All blocks
which must be changed are written contigiously to
a new area of the disk, and then "linked in" in a
single atomic step. This allows you to achieve close
to the streaming write performance of the disk,
by always writing new blocks in contigious regions.
A small amount of overhead is incurred because you must
also rewrite all indirect blocks which point to the
new datablocks, all the way up to the superblock.
Networking:
Exokernel Packet dispatching filters: The MIT Exokernel
has a novel networking stack design which allows
truly-layered protocol handlers, without terrible
performance penalties. This is achieved by uploading
small 'packet filtering programs' (written in a
custom language so they are safe) into the kernel
which can identify packet types and subtypes.
The kernel merges the filter programs into a single
'test tree', so that it does not have to repeat
byte value comparisons.
Programming Languages:
String Handling:
Python's "%" operator: Python introduced '%' as a
binary operator on strings. This allows any code to
easily do sprintf() style formatting in a visually
compact, yet readable fashion. It has a better
performance basis than C++'s cout<< overloading,
because it's a single function call per format
string, not per element added. It also supports named
format elements if handed a
hash-table instead. For Python the trick of keeping
this a simple binary operator lies in the existance
of a "tuple" type which holds an arbitrary number of
elements. For other languages, this would be
equivilant to an operator with a variable number of
arguments.
Ex: "Hey %s, how are you today?" % dave
"%d rats, %d cats" % (rats,cats)
Type-Conformance/Interfaces:
Sather's implicit interface definition: Sather has a
unique feature where every class implicitly declares
an interface with the type of the class. This means
that you can always write a type-compatible replacement
for a class which inherits no code. It also removes
the odd trouble of people testing for "object is a class"
when they should be testing for "object implements an
interface", because the former does not exist.
In [all] other strong typed programming languages,
if a library makes use of a certain class, and they
don't think to declare it as an interface or
abstract class, then you are stuck using their
implementation instead of yours.
Of course for this to be truly useful, you need to
be able to bind in a new version of the class to the
global class factory, so when the library creates
a "new" instance, you can provide a different class.
(see .NET assembly binding)
Type Binding:
C/C++ style inherited type context: In the C/C++ days
of #include(ing) header files, when a programmer
#included a library API, that library API in turn
normally included the headers of its dependencies.
This meant that one could include one base object
header, and easily make use of all return types and
necessary argument types. For example:
// C++
#include <HttpFetch>
void do_fetch(void) {
HttpFetch aFetch =
new HttpFetch(new URL("http://www.yahoo.com/"));
Stream myResult =
aFetch.getResult();
char buf[200];
int read;
while (read = myResult.read(buf,199)) {
buf[read]=0;
cout << buf;
// ...
}
}
Header files have slew of problems which needed to be
fixed. However, as modern languages replaced
headers with namespaces and module systems,
somehow the programmer was saddled with the
extra work of importing not only the module
he was using, but also all the modules which
contain arguments and return types he needs
to use. This makes the import section a chore
instead of a tool, because (a) the programmer has
to dig up what modules the return types are
declared in and (b) it no longer simply explains
the root of dependencies for this file. For
example:
// Java / C# esq
import System.Web.Http.HttpFetch;
import System.Web.URL;
import System.FileIO.Stream;
void do_fetch(void) {
HttpFetch aFetch =
new HttpFetch(new URL("http://www.yahoo.com/"));
Stream myResult =
aFetch.getResult();
print myResult.read();
}
Extension of existing (Binary) Classes: Objective-C
introduced the concept of loading a set of new
methods onto an existing class. This was called
'Category-Loading', and it allowed an existing class
to be extended. COM nearly provides a similar mechanism
through a pattern called Object Aggregation. In this
pattern, a COM Interface is merged into an
existing object, without the implementations being coupled.
SELF provided a similar pattern called 'traits' or 'mixins'.
Finally, TOM provides an formal extension mechanism
whereby you can add or replace method implementations
in an existing binary class after the fact.
This type of aspect provides some of the same features
as Multiple Inheritence without many of the drawbacks.
Aspects like this allow for the useful extension
of built-in classes (such as adding a new type of
string formatter to Strings, or a new method of
serialization to other objects).
Aspects like this also allow for a different type of
code reuse I think of as 'top-half code reuse'.
Instead of reusing a library in two applications,
top-half code-reuse is a means by which you repurpose
an application by giving the library it uses new
functionality. One powerful means by which you can
do this is by extending an existing class with a few
new methods which only need to be called in isolated
places. This allows your application to function as
before, and your new methods let the class do new
things. (such as adding printing functionality to
your app by adding a .targetTo(printer) method
to the base View class). In languages without
class extension mechanisms, If you do not control
the source code to the base-classes, and classes
are being instantiated elsewhere, this type of
resuse is impossible. Categories, or other
extensions allow you to extend that classs anyhow.
.NET Assemblies: In .NET code is provided in the
form of an Assembly. Each DLL is an Assembly, as
is your application itself. The .NET runtime keeps
track of the types bound to each assembly, so that
when an assembly instantiates a new object, it
gets an object of the type bound to that individual
assembly. This allows more flexible ways for different
versions of code to live harmoniously together.
For example, you import a library which internally
needs to use "v1.0" of "HtmlStringBuilder", but your
code also needs to use v2.0 of "HtmlStringBuilder".
As long as you don't need to pass the class across
the boundary between their code and yours, everything
works great and nobody is the wiser. In other runtime
environments (like Java, and in rare cases even in
standard UNIX shared library binding) this versioning
can become a problem.
Packaging:
Nextstep app-wrappers and bundles: Nextstep grouped
all application datafiles into a single item known
as an "app-wrapper". While the wrapper was merely
a special directory, this drastically simplified
application installation and management. Application
data was distinctly divivided into (a) non-mutable
data-files and libraries supplied inside the
wrapper, (b) user preference data which is stored
through a specific api which abstracts away the
storage location, and (c) the document datafiles
for the application.
Nextstep's passive type-registry: Instead of managing
a central mime-type registry through application
installers, and manual coordination, such as in the
Windows registry, Nexstep required applications to
passively export information about mimetypes and
other exported services. This assured that
applications themselves are easily installed, merely
by copying the application to a new location, and are
easily uninstalled, by merely deleting the application.
A central type-registry cache is generated by scanning
available application wrappers. In this system
there is no central Windows-registry like database to
be managed or become out of date. It also means that
applications are easily relocated by merely copying
them to a new location, without making them out of date
with respect to central registry entries.
Sadly, while this scheme provides elegance in
the new MacOS X, KDE and Gnome have not yet
adopted it.
Java JAR files: Java allows application files to be
joined together into a single ZIP archive. This
archive can contain not only code binaries, but also
a hierarchy of images, sounds, and any other required
application data. This drastically simplifies the
distribution of application files, and enforces
non-mutable application data.
Run-Time execution Optimization:
SELF's Hotspot VM (later turned into Java's HotSpot VM):
SELF is a fully weak/dynamic typed language akin to
Smalltalk in base execution speed. To speed up execution,
the SELF team developed a dynamic run-time compilation
and recompilation system which would (a) profile the
types which actually occur at polymorphic type sites,
and (b) compile custom versions of method calls which
were optimized for popular types (with downstream
code inlined!).
Since SELF is a weak typed language like
Smalltalk, all type sites are polymorphic, and this lead
to large amounts of memory overhead. However, a similar
method might be employed on a simpler static/strong
typed language which would allow all methods to be
considered virtual, while making code use static jumps
(instead of indirect jumps) for (a) virtual methods
which are not overridden in any loaded classes, or
(b) inner-loop call sites where a small number of
classes are frequently present.
Elegance of Expression:
Aspect Oriented Programming (as in AspectJ for Java):
Xerox PARC developed a method of keeping code small
while added whole-program optimization 'aspects' by
using an AspectWeaver to combine the simple logical
program with it's whole-program aspects, and output
the much larger final program code.
This method seeks to buck the trend that the first
10% of the work gives you 90% of the solution, while
the remaining 10% of the solution makes up 90% of
the work. For example, a simple image processing
algorithm expressed in scheme might be only 80
chararacters long. However, to implement an efficient
version of that algorithm in C with tuned buffer sizes
and processor specific SIMD instructions, would
require far more code. AOP seeks to have those
other optimizations expressed just a simply and
concretely, and let the AspectWeaver do the work
of weaving together the simple aspects and your
simple algorithm into a complex program.
User Interface:
Folder Navigation:
'drop folder to go there': Apple Nav Services (OS 8.x) and
BeOS allowed you to drop a folder icon onto an open or
save panel to have the panel go there. This provided
a needed bridge between the finder UI and the open/save
panel. Without it, saving a document into a folder which
you already have open in the finder can be an annoying
experience.
Shelves: Several systems have created intermediate mechanisms
for drag-and-drop operations. First you grab the
item and drag it to a temporary location, then you
go find the target, and drop on the target. This prevents
you from having to open both the source and the target to
perform a drag-and-drop operation. Sometimes these shelves
allow you to locate commonly used items centrally for
frequent use. Nextstep's filemanager is the best
shelf-implemenation I've used. It allowed you
to drag groups of files or folders onto a 'shelf' area at
the top of a filemanager window. The Apple newton
used the side of the screen as a shelf for clipboard
opeations. IBM's OS/2 allowed you to right-click and
'pickup' an object into a single-item shelf attached to
your pointer. You could navigate around as normal, and then
finally 'drop' the item you were carrying. Apple's
edge-of-screen folder docking is another form of shelf.
in OS 8/9 you can drag a folder to the side of the screen
where it will become a tab. Clicking or dragging over
the tab will open the folder.
Spring loaded folders: MacOS drag-and-drop behavior
introduced a method known as spring-loaded folders. While
dragging a file to a destination, hovering briefly over
a folder icon would cause that folder to spring open,
allowing you to zip through several levels of hierarchy
while dragging. I personally prefer shelves.
Windows/Nextstep style separation of path and filename:
Keyboard navigation is an important part of the
advanced user experience in any system. In order to
be able to keyboard navigate the filesystem from a
Save Panel, one needs to be able to keyboard
nagivate the paths without erasing the suggested
filename. Windows and Next (now MacOS X) both have
this correct. However, the majority of Save panels
on UNIX, from Motif to GTK, erase the the text of the
suggested filename when you use keys to navigate the
directory structure. Some of them even erase the
filename when you select a directory with the mouse!
Misc UI:
'Inspector' Floating Windows: NeXTStep first formalized
the concept of a app-specific floating inspector
windows. To make this work, they introduced the concept
of their being two 'active' windows on screen, one
is the main window (the selected document window),
while the other is the key window (where you input
focus is). When selecting an inspector, the last
selected document window is the main window, while the
inspector is the key window. This allows the capability
for proper keyboard focus, and reasonable user feedback,
while using a floating window.
One drawback of this scheme (and the Mac/Next
single application menu metaphor) is it's
incompatibility with the common power-user's 'Focus
Follows Mouse' window focus behavior.
Dialogs:
'Window Attached Dialogs': MacOS X introduced the concept
of Dialog Sheets. This allowed a Modal dialog to
apply to only a single window by attaching itself
to that window, partially obscuring view of the window.
This makes far more sense than arbitrarily locking up
an entire application because of an operation which
really only affects a single window.