Thu, 29 Sep 2005

Currying isn't just a mathematical innovation; it's also a user
interface technique.

My Angle on Current UI Techniques
---------------------------------

"Forms" --- text widgets, checkboxes, radio buttons, sliders, buttons,
that sort of nonsense --- allow a person to create data in a computer
program, and to instruct it to take actions on their behalf.  They
don't really help much for direct manipulation, though, where the data
is already inside the computer --- perhaps as some kind of smart
object inside a computer program --- and the person wants to
manipulate it somehow.

That's because generally such manipulation involves simultaneous
selection of at least two objects: an object to act on, and an action
to take on it.

The primary computer UI techniques for that so far follow, in order of
increasing directness:
- indirect manipulation: the person's subjective experience is that
  they instruct a computer program what to do with the data.  For
  example, they might write a program in a language with instructions
  to manipulate various objects.
- verb modes: the person selects a "tool" that interprets their later
  clicks.  For example, in a drawing program, the person might click
  an "erase" icon, causing their subsequent mouse clicks and drags to
  erase things from their drawing.
- noun modes: the UI is focused on one primary object, and there are
  secondary objects sitting around that the person can, say, click on.
  When clicked on, they perform some action on the main object.  For
  example, you might select some text (the primary focus) and then
  click on a "cut" menu option (the secondary object); or in
  Hypercard, when you create a link, it adds a floating button to your
  screen (the secondary object), and when you have navigated to a card
  (the primary focus), clicking the button directs the link to that
  card.
- drag-and-drop: the person drags one object (generally the noun) onto
  the other (generally the verb).

In any of these techniques, the set of nouns may be either open or
closed, as may the set of verbs.

Currying With Current UI Techniques
-----------------------------------

Currying extends any of these techniques, including drag-and-drop, to
arbitrary numbers of objects.  Hypercard's "link to this page" button
is an example: there's a "make link" menu item (marred by a modal
dialog box, but no matter) which creates a new verb in the UI, and
that verb is a curried procedure: "make link from <some particular
place> to currently viewed card."

Robb Beal's experimental Mac OS X "Spring" user interface for the Web
used drag-and-drop for a variety of communication actions.  But to
select which action to take, Spring would pop up a menu after a drag
was completed, for selection of the action, because all of the objects
displayed in Spring canvases were nouns, not verbs.

Drag-and-Drop and REST
----------------------

Drag-and-drop maps well onto REST.  A drag-and-drop UI contains only
three user actions: display an object, invoke an object with no
arguments (by clicking or double-clicking on it), or invoke an object
with one argument (by dragging another object onto it).

This is particularly important because the existing REST UIs (i.e. web
browsers) are utterly impoverished in their ability to submit one
resource, or an entity obtained from some resource, to some other
user-selected resource; and they are utterly incompetent at managing
user-created data.

A REST-Backed Drag-and-Drop UI
------------------------------

I propose a spatial REST UI, which would interoperate with the
existing WWW as a sort of awkward browser, but would allow new kinds
of web-based applications to be built.

The objects arranged on the user's canvas are either resources
(identified by URL) or entities.  Resources are displayed with an
entity obtained by dereferencing them (e.g. HTTP GET) or, failing
that, just as a URL and perhaps some link text.  The user can easily
collapse the display down to just the title and favicon.

An HTML entity usually has links to other resources within it;
clicking on these links, or dragging them onto the canvas, will add
those resources to the canvas.

The data in an HTML form is a separate entity from the HTML itself.
Typing into the form creates a clone of that entity, which is
positioned on top of the original HTML page; the form can be submitted
to its ACTION URL in the usual way, or to some other URL by dragging
it onto that other URL, resulting in an HTTP POST (or GET) to that
other URL.

Dragging one resource onto another performs an HTTP POST to the URL of
the second resource of a form with one field: "dropped_url", with the
value of the first resource's URL.  (Perhaps it should also include a
representation, particularly for private resources?)

It's generally desirable for a drop-target to provide visual feedback
about whether it's a suitable target for a particular dragged object;
this reduces user errors.  Traditionally this is done with type
information, but that doesn't work that well in the world of the web;
most web pages have the same MIME type, and if someone else doesn't
like the MIME type you got, they may be able to content-negotiate for
a different representation of the same resource.

The web equivalent of WSDL or IDL is the HTML form; it specifies the
set of inputs required for a "remote call" in a machine-readable form,
including possible values for those selected from a finite set; it
normally includes human-readable documentation about those same
arguments; and it may even include machine validation rules.  So it
seems that the most harmonious place to put this drop-target feedback
is in an HTML form.

At the least, you could grey out resources whose GET representation
doesn't have a form with a variable named "dropped_url".  Perhaps
JavaScript in the form could be given a representation for the
resource and decide whether it was interested.

An Example Application
----------------------

I'm looking at a web page about Tim Burton's film, "Corpse Bride".  I
decide that I want to bookmark it, so I drag the web page onto the URL
for my bookmarking service.  This form POST creates a new resource (my
bookmark) and redirects me to it with a 303 See Other response, which
appears on my canvas next to the bookmarking service.  I add some
annotation ("raw images from digital cameras with dcRAW") by typing
into a form; as I begin typing, a border appears around the form,
because it's just been copied into a new window positioned on top of
the previous one.

At this point, my computer crashes, and I reboot.  When I restart my
REST canvas, it looks the same as before the crash, including the
un-submitted form data.

I'm not sure about the spelling, so I drag the form data over to a
spell-checking resource.  A marching-ants arrow appears from the form
data to the spell-checking resource and my annotation data is
submitted to it as a form POST; after checking the spelling of all the
form fields in its request, the spell-checking resource responds with
a very short HTML document: "Spelling OK.", which appears next to the
spell-checking resource.  The arrow disappears, but the form data
remains visible.

I finish typing the annotation and hit "Enter".  The form now submits:
an arrow appears from it to the titlebar of the web page and does the
marching-ants thing for a second or two.  The web server sends another
303 See Other, to the same URL, which causes the canvas to refresh its
view of the resource, reflecting my changes; and the form data window
that's obscuring it animates over to the trashcan and disappears
within.

Had I submitted it by dragging it onto its original resource, it would
not have disappeared from the screen.

Now I want to tag my bookmark with the tags "video", "media", and
"free-software".  I pop open a part of the canvas containing
commonly-used tags; I drag the "free-software" tag onto my bookmark.
This results in an HTTP POST to the bookmark resource, which fetches
the "free-software" tag's URL, recognizes it as a tag to be applied,
and responds by modifying the bookmark and sending another 303 to the
bookmark, which again refreshes my display.

Now, I always apply the "media" tag to anything I tag as "video".  I
have separate "media" and "video" tags, so I decide to automate the
combination.  I have a collection of "foreach" resources on my canvas.
I pop open the "foreach noun" resource and read the description and
conclude that it's the right one.  I click the button in its
description, and it does an HTTP POST to create a new "foreach noun"
collection, which (after a 303) appears next to it on my canvas.  I
drag it over to my "tags" area and pop it open; its description has a
link to the generic "foreach noun" resource, and links to a subsidiary
resource, "add to collection".  I drag "add to collection" onto the
canvas, and then drag "media" and "video" onto "add to collection".
Each drag results in a 303 back to the collection, which refreshes and
shows me its contents.  I edit its description with an inline form:
"media+video".

Now I click the "Collapse" button on the collection's representation
to collapse it back to just its favicon and title, "media+video".  Now
I can apply this "foreach noun" collection to any verb by dragging the
verb onto it.

So I drag my bookmark onto "media+video".  This results in an HTTP
POST to "media+video" with the URL of my bookmark.  (I'm assuming this
URL is secret, so knowing the URL is sufficient proof of authority to
edit.)  Now the "foreach noun" server does two HTTP POSTs to the
bookmark, one with the URL of the "media" tag and one with the URL of
the "video" tag.  Since the two HTTP responses are identical, it
returns one of them to my canvas, which responds by refreshing the
bookmark, which now has two more tags.  (I'm not sure what it should
do with different responses.)

(It's a little awkward that the drag direction here is backwards from
the normal tag dragging direction.  This is an inherent problem with
this UI, I think.)

I want to email my annotations to the author of the article.  I drag
their mailto: link out of the article onto the canvas; I click on my
bookmark's edit form to extract the form data as a separate entity.  I
drag this entity onto the mailto: link, and it creates a new "email
message" entity on my desktop next to the mailto: link, containing all
the form data.  I drag the form data itself to the trashcan to make it
disappear (so it stops obscuring the bookmark page), edit the mail
message, and hit the "send" button to send it.

Other Directions, Briefly
-------------------------

Other generic services that make sense with this UI, other than "spell
check", "bookmark", and "foreach noun":
- foreach verb
- Wayback Machine
- Alexa page rank for domain
- Google backlinks for URL
- Technorati search for URL
- automated translators
- add popup links to Chinese character translations
- pipeline: contains a sequence of verbs; feeds the output of one to
  the input of the next.  (Probably has options for some minimal
  translation, such as extracting form data or encapsulation in a form
  field, since most existing web services don't know what to do with
  an HTTP POST with content-type text/html.)
- verb chain of responsibility: try dropped URL on each verb until one
  returns success
- noun chain of responsibility: try dropped verb with each noun until
  it returns success for one of them
- form field renaming
- makeashorterlink-type services
- simple concatenation of page contents

Other URL schemes other than HTTP:
- aim
- mailto
- file

Other directions:
- support asynchronous invalidation, so web pages can be "live"
  - or at least let you manually configure polling, as Opera has for
    years
- support non-spatial layouts, such as nested hboxes and vboxes
- perhaps "titlebars" should be "tabs" that are placed on any of the
  four sides of a representation so as to be visible

Credits
-------

Inspired by Naked Objects.  Inspired by Spring.  Inspired by
Hypercard.  Bookmarking scenario from del.icio.us.  End users wiring
together web services inspired by Marty Tenenbaum.

Wed, 28 Sep 2005

I'm responding to the question, "So how do I code up addition, or
anything where you want to take arguments other than this?", from
http://calculist.blogspot.com/2005/06/classicjavascript.html --- with
regard to Abadi and Cardelli's object calculi.

This is explained in a slightly different notation than Abadi and
Cardelli use for their object calculus.  I'm leaving out the syntactic
sugar I usually use in order to keep this explanation simple for those
who haven't read Abadi and Cardelli.

    {} is an object with no methods.

    self.foo = self.bar + 1 is a method whose definition is "call bar
    on the same object, then add 1."  Abadi and Cardelli write this as
    "foo = sigma(self) self.bar + 1".

    x.foo = x.bar + 1 is the same method (or, if you prefer, another
    method that behaves identically.)  This expression lexically binds
    the name 'x' within the method definition to the "self" parameter
    --- the object the method is called on.

    x{ self.foo = self.bar + 1 } is an override expression; it means
    "an object exactly like x, except that it has this new foo
    method," which is defined as above.

    I'll separate methods inside objects or override expressions with
    newlines or commas.

    I've also added new methods to objects in override expressions
    without restraint; you can rewrite this code so that it only ever
    overrides existing methods, as in Abadi and Cardelli's work,
    without much effort, simply by adding useless method definitions
    in objects whose descendants do this.

So here are booleans:

{
  booleans.true = {
    self.negated = booleans.false
    self.ifTrue = { x.then = 1, x.else = 0, x.val = x.then }
    self.ifFalse = self.negated.ifTrue
  }
  booleans.false = booleans.true {
    self.negated = booleans.true
    self.ifTrue = booleans.ifTrue { x.val = x.else }
  }
}

If "hungry" is a variable that might be one of booleans.true or
booleans.false, we can say

  hungry.ifTrue{ x.then = "eat", x.else = "don't eat" }.val

Suppose hungry is the above 'true'.  This resolves to

  {
    self.negated = booleans.false
    self.ifTrue = { x.then = 1, x.else = 0, x.val = x.then }
    self.ifFalse = self.negated.ifTrue
  }.ifTrue{ x.then = "eat", x.else = "don't eat" }.val

and then

  { 
    x.then = 1, x.else = 0, x.val = x.then
  }{ 
    x.then = "eat", x.else = "don't eat" 
  }.val

which reduces to

  { x.then = "eat", x.else = "don't eat", x.val = x.then }.val

Which resolves to 'x.then', with 'x' being the above-constructed
object whose 'then' is defined as "eat".  Supposing instead that
hungry were 'false'; instead we get

  booleans.true {
    self.negated = booleans.true
    self.ifTrue = booleans.ifTrue { x.val = x.else }
  }.ifTrue{ x.then = "eat", x.else = "don't eat" }.val

If we expand out the booleans.true here, we get

  {
    self.negated = booleans.false
    self.ifTrue = { x.then = 1, x.else = 0, x.val = x.then }
    self.ifFalse = self.negated.ifTrue
  }{
    self.negated = booleans.true
    self.ifTrue = booleans.ifTrue { x.val = x.else }
  }.ifTrue{ x.then = "eat", x.else = "don't eat" }.val

And then if we evaluate the first override expression, we get

  {
    self.negated = booleans.true
    self.ifTrue = booleans.ifTrue { x.val = x.else }
    self.ifFalse = self.negated.ifTrue
  }.ifTrue{ x.then = "eat", x.else = "don't eat" }.val

since the only method from 'true' not overridden in 'false' is
ifFalse.  Now we can evaluate the .ifTrue method call and get:

  booleans.ifTrue { x.val = x.else }{ x.then = "eat", x.else = "don't eat" }.val

which expands out to

  { 
    x.then = 1, x.else = 0, x.val = x.then
  }{ 
    x.val = x.else 
  }{ 
    x.then = "eat", x.else = "don't eat" 
  }.val

We can collapse the first override and get

  { 
    x.then = 1, x.else = 0, x.val = x.else
  }{ 
    x.then = "eat", x.else = "don't eat" 
  }.val

and then the second, and get

  { 
    x.then = "eat", x.else = "don't eat", x.val = x.else
  }.val

And that reduces to just 'x.else', which is defined as "don't eat".
This is exactly the same as the last reduction step for when hungry
was 'true', except that we inherited a different definition for
'x.val'.

Now, for numbers.  A real implementation of this object-calculus on a
computer would use the CPU's rapid number-handling machinery rather
than implementing its own math primitives, and the method I am about
to explain is a terribly inefficient way of implementing them anyway;
its purpose is to demonstrate that the object-calculus can
theoretically perform any computable computation on its own.  The
following technique is just a transliteration of the lambda-calculus's
Church numerals.

Here's an object containing numeric primitives; I assume the earlier
booleans object is available under the name 'booleans'.

{
  numbers.zero = {
    self.isZero = booleans.true
    self.plus = numbers.sum { x.firstArgument = self }
    self.succ = self { 
      succ.isZero = booleans.false
      succ.pred = self 
    }
  }
  numbers.lessThan = {
    self.firstArgument = numbers.zero
    self.secondArgument = numbers.zero.succ
    self.val = self.secondArgument.isZero.ifTrue {
      x.then = booleans.false
      x.else = self.firstArgument.isZero.ifTrue {
        x.then = booleans.true
        x.else = numbers.lessThan {
          child.firstArgument = self.firstArgument.pred
          child.secondArgument = self.secondArgument.pred
        }.val
      }.val
    }.val
  }
  numbers.sum = {
    self.firstArgument = numbers.zero.succ
    self.secondArgument = numbers.zero.succ
    self.val = self.firstArgument.isZero.ifTrue {
      x.then = self.secondArgument
      x.else = self {
        child.firstArgument = self.firstArgument.pred
      }.val.succ
    }.val
  }
}

The above definitions should evaluate 

    numbers.zero.succ.succ.succ.plus { 
      x.secondArgument = numbers.zero.succ.succ.succ.succ
    }.val

to the same thing as numbers.zero.succ.succ.succ.succ.succ.succ.succ.
But I may have made a mistake.

So the short answer is that methods often return an object not derived
from self, but some of whose method definitions are closed over self.

As I've implied previously (in "functional programming for amateurs in
an outliner", before I read Abadi and Cardelli's book --- thank you
David Gibson!) I think this is the theoretical underpinning for
dramatically more usable and productive programming environments.

Links:

> Abadi and Cardelli's object calculus is described in the first three
  pages of "A Theory of Primitive Objects" at
  http://research.microsoft.com/Users/luca/Papers/PrimObj1stOrder.pdf
> "functional programming for amateurs in an outliner" is at
  http://lists.canonical.org/pipermail/kragen-tol/2002-May/000713.html
> "towards a modern programming environment" is at
  http://lists.canonical.org/pipermail/kragen-tol/2003-May/000745.html
> Also related is Jonathan Edwards' Subtext:
  http://subtextual.org/
> And Wouter van Oortmerssen wants "abstractionless programming", the 
  same thing:
  http://lambda-the-ultimate.org/node/view/17
> And Dynamic Aspects' "domain/object" platform seems to be a larger 
  idea including the same kernel:
  http://www.dynamicaspects.com/