Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 01 Sep 1997 08:21:55 -0400
From:      Bakul Shah <bakul@torrentnet.com>
To:        "Jordan K. Hubbard" <jkh@time.cdrom.com>
Cc:        freebsd-chat@FreeBSD.ORG
Subject:   Re: sysinstall (was Re: Conclusion to "NT vs. Unix" debate) 
Message-ID:  <199709011221.IAA19858@chai.torrentnet.com>
In-Reply-To: Your message of "Sun, 31 Aug 1997 23:16:28 PDT." <7098.873094588@time.cdrom.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
> Perhaps I'm just biased from my previous installation experience, but
> the way I see this working is as a series of linked "black boxes",
> each black box representing some functional block of installation
> hackery with an API for getting/setting its internal state and
> executing it.  You allow boxes to be named, to depend on other boxes
> and to be arbitrarily chained together themselves. A "novice install"
> then becomes a simple matter of creating a chain of operations and
> starting the user off at the head of it.  You'd have some sort of
> "escape mode" which allowed the user to jump up a level and examine
> this operation chain, moving forwards or backwards and perhaps able to
> distinguish completed from uncompleted actions by their appearance.

Seems like a `frame' data structure would nicely represent
one of your black boxes!  [For the unfamiliar:]  A frame has
a set of named `slots', a slot has a set of named `facets',
a facet can have a list of values.  A value can be pretty
much anything including a reference to some other frame.

A frame's slots (properties) or facets (sub properties) can
be inherited, defaulted or computed.  You can add, change or
delete any number of slots, facets or values at any time.
The process of adding/deleting can also be made to trigger
other changes. This flexibility, coupled with a rich set of
get/set functions (see below) make it a very useful data
structure in situations where a lot of information has to be
inferred.

For instance, you can define a generic display-frame like so:

display-frame: {
    background-color: {value: {white}}
    foreground-color: {value: {black}}
    next: { display: {button} location: {"-1-1"} action: {select-next} }
    prev: { display: {button} location: {"-1+1"} action: {select-prev} }
    clear: { display: {button} location: {"-1+20"} action: {clear-all} }
    help: { display: {button} location: {"-1+40"} action: {show-help} }
}

When this frame is given to some display procedure it will
interpret the frame's contents and display all slots that
have the display facet.  It will attempt to display slots at
per their location facet.

The first two slots are obvious.  The next four slots define
action buttons if a correponding button is pressed.  An
action facet can be a procedure that is given the calling
frame, slot and facet.  The select-next function can choose
a different next frame depending on the user (novice or
expert).  Alternatively you can define two facets:
novice-action, expert-action.

Now a frame that requires the above behavior can be defined
simply as:

foo: {
    a-kind-of: {value: {display-frame}}
    help: {value: {"this is a foo frame"}}
    ...
}

The a-kind-of slot can be used to inherit from multiple
frames.  When foo is given to display(), its contents as well
as its inherited contents are displayed.  When the help
button is pressed, {foo,help,action} is passed to show-help,
which can extract foo.help value and display that.

> Sysinstall also currently requires that each functional block roll its
> own GUI more or less from scratch - that's painful.  It'd be a lot
> nicer if you could simply say that each block had some attributes and
> when you "visited" one, more generic attribute editing code could take
> over the job of presenting the appropriate dialogs.  You have some
> known attributes for designating whether a block can be undone or has
> gone past the point of no return, etc. and so forth.

Yup.  This is easily possible.  Slots that can be edited can
have a edit facet.  Instead of undoing an action you can
simply wait till all the information is filled in or inferred
before doing anything.  The beauty of a frame is that it has
a very regular structure so adding more attributes etc. does
not require you to change a struct definition or worry about
how to make two structs compatible when they differ only
`slightly'.  Since every object can be used as a prototype
for some other object you can dispense with a lot of
bookkeeping ala C++.

-- bakul

PS:  Frames were first described in a 1975 paper by Marvin
Minsky -- I believe you can get a scanned copy of this paper
from some mit site.  They are also described in some Lisp
books.  Frames are almost always implemented in Lisp but I
see no reason why they can't be implemented in other
languages or why such a rich data structure should be left
alone for the use of AI heads :-)  In C you can't define
functions on the fly but that should not be a problem in tcl
or perl.

The basic frame functions are 

get-fsf(frame-name, slot-name, facet-name)
    returns values corresponding to the frame-slot-facet triple.
    or NULL if no such value exists
set-fsf(frame-name, slot-name, facet-name, value)
   adds to the value list for the frame-slot-facet.
   also creates frame, slot and facet if missing.
del-fsfv(frame-name, slot-name, facet-name, value)
   deletes value if it exists.
   deletes facet if no values left.
   deletes slot if no facets left.
   deletes frame if no slots left.
get-fs(frame-name, slot-name)
    same as get-fsf(fame-name, slot-name, "value")
get-fsd(frame-name, slot-name)
    in addition to what get-fs does, it also looks in the
    "default" facet.
getI(frame-name, slot-name,facet-name)
    same as get-fsf but if that fails, it walks up the
    a-kind-of tree to extract the facet.  This would be an
    *Inherited* facet, hence the getI name.
getN(frame-name, slot-name)
    same as getI(frame-name, slot-name, "value")
    but if no value was found, it then tries
    getI(frame-name, slot-name, slot-name, "default")
    and if that fails, it tries
    getI(frame-name, slot-name, slot-name, "if-needed")
    The last getI may return a function, which when evaluated
    will yield the actual value.  The `N' in the function
    name to remind us that first we walk  up the a-kind-of
    tree, then come all the way down and try it again with
    a different facet, walking up again and so on.
getZ(frame-name, slot-name)
    this function goes across first and then up.  That is,
    try get-fsf(frame-name, slot-name, "value") or else
    try get-fsf(frame-name, slot-name, "default") or else
    try get-fsf(frame-name, slot-name, "if-needed") or else
    for each f in get-fsf(frame-name, "a-kind-of", "value")
    try the same three facets.
set(frame-name, slot-name, facet-name, value)
    like set-fsf.  In addition it will also invoke an
    "if-added" facet procedure for slot-name if one exists or
    can be inherited.  This way changes in one frame can be
    made to side-effect anything else.

del(frame-name, slot-name, facet-name, value)
    like del-fsf.  In addition it will also invoke an
    "if-removed" facet procedure (which may be inherited) if
    one exists.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199709011221.IAA19858>