------------------------------------------------------------------------------
[MOOSE Specificating tools]


THE BIG QUESTION, always discussed, and not agreed upon already:
===============================================================
  Of course, we must use some high-level tools to build MOOSE
(we're not going to program it directly in hexadecimal as in the
early Apple ][ days !). So,

	<<WHAT ARE OUR LANGUAGE REQUIREMENTS ?>>
	<<KNOWING THAT, WHAT HIGH-LEVEL LANGUAGE(S) TO CHOOSE ?>>

LANGUAGE REQUIREMENTS:
=====================
The language issue is central in the OS.
All the OS' semantics will depend on the choice of the language.

Ideally, the semantics of the two should be equivalent: that is, any
 construct made available by one must be directly mappable on the constructs
 of the other (that it will actually be thus mapped is another question).

	* Of course any existing language may be implemented over the
	 system (it's Turing-equivalent, and offers the usual IO facilities).
	* The problem is which language will match the OS' semantics.
	* It appears that the language should be open, offer partial
	 evaluation, admit side-effects and parallel processing, object
	 annotation. It should rely on primitives simple enough so that
	 program specifications are a feasible thing, yet offer a back door
	 to unsafe programming (unless we're specifying the whole hardware
	 before we write anything in the language using the given hardware).

Big Questions:
-------------
Q1	* What kind of interface and functionality do we want/need?
A1 (partial answer)
	* NEED: None; a turing machine (what current OSes already provide)
	 is enough for all possible computing in the world.
	* WANT: hey, that's the point. We're so free we must restrict
	 oneselves. We can choose our own bounds.

Q2	How does adding classes/objects to the system work?
R2	That's what we'll be discussing below.


Features thrown out:
-------------------

(temp. note: I've put there text from Michael's letter, and almost all the
		4.3 from my previous letter)

*** Door to a secure parallel execution in an OO language *** [first proposed]
Michael original: (not contradicted, enhanced by Fare next)
	* We need memory management and memory protection.
	* We want multitasking.
	* A simple kernel would support these standard things and in
	 addition would recognize ``objects'' and ``classes''

Fare's Proposed enhancement: (not contradicted; to be agreed upon on next
				meeting)
	* why not have multitasking, memory management and protection
	 as objects among others (well, with a low-level implementation,
	 but the same interface to the kernel) ?
	* Our kernel would just be the object/class calling convention.
	 All other features will be considered the run-time library.
	* There will be objects to manage tasks and memory management.
	 The kernel itself may not even be conscious of these, only knowing
	 about how to call other objects !

PROs:	* We need the language to be parallel-execution aware, as if we
	 want multitasking, we should be able to declare in a simple way
	 what objects are shared (C's shared memory segments: _yeech_, and
	 unsecure).

*** Low-level ability *** [proposed twice]
	* low-level things cannot be banned from the system.
	 On the opposite, this means a same high-level concepts can have
	 plenty of different low-level realization,
	 and not only one as on older low-level languages;
	 efficiency details can be thought of afterwards and
	 separately in each particularization.

*** High-level -> low-level mapping *** [proposed twice]
	* This means the language, should not enforce its own
	 implementation for abstract types, but rather let the user
	 implement his own.
	* Again, this does not mean you will have to write each time
	 both the high-level definition and the low-level
	 implementation each time you define a new object (as current
	 OO languages want you to do), as the language system
	 (interpreter/compiler/whatever) can automatically provide one
	 straightforwardly (or subtlely :) computed for you.
	* This works by annotating an object by several functionally
	 equivalent versions, though not as efficient according to
	 the particularization you want to give it. An "equivalence"
	 constructor is a very important construct in the language.
	 Thus you can equate an object to its implementation in
	 several different languages (or many times the same in
	 different ways), not all of which may be understandable by
	 the version of the system you're working on (e.g. an equate
	 of a function in english gives a good documentation, even
	 if ununderstandable by any computer system yet).
	* Of course, such equates can or not be automatically generated
	 and/or modified by the language system.
	* we stress that [4.3.1] must be understood so that not only the
	 implementation language and algorithm, but also the
	 abstract-object/implementation-realization correspondance,
	 i.e. the calling convention, can change. Thus, proposed
	 implementations in libraries/precompiled versions of objects
	 will have been optimized internally, and the linker will
	 automatically generate the code to call an imported function.

*** Security *** [proposed twice]
	* Mutual protection of objects from others can be done both
	 at run-time and compile time. Removing run-time checking
	 is a great factor of speed and space optimization. Thus,
	 Running objects without (or with limited) run-time protection
	 is an important feature to provide to the loader.
	* Again this can be done by annotating objects by property they
	 do or should have, then relying on properties they have been
	 *proved* to have to eliminate checks when implementing them.
	* A super-user is someone the computer trusts enough to consider
	 that some property is proved just because the super-user told him
	 so insistently.

*** Partial evaluation ***
	* More general than a linker is a code specializer (partial
	 evaluator), that also contains the "optimizing" module: it
	 takes a generic object and some additional bindings, and
	 returns a new version of the object specialized with those
	 bindings.
	* A dynamic compiler/linker is the true heart of the system, while
	 the traditional service-providing "kernel" is only a (basic,
	 necessary) library, a replaceable extension to the system.

*** Annotations ***
	* We saw that all these features could be implemented on a kernel
	 that only manages ANNOTATIONS: you annotate an object by how to
	 use it, what properties it has, etc.
	* You may almost freely add annotations to any object you are given
	 access, and modify them in a *LOCAL* scope. Accessing a more global
	 scope is done by using objects exporting side-effects.


Objects & Classes:
-----------------
Michael:
  What is an class? From the point of view of the kernel,
 it's a piece of code with
	(a) multiple entry points
	(b) An attached description of these entry points and their types.
	(c) An indication of inheritance (more thought needed on this one)
  What is an object? From the point of view of the kernel it's a data region
 with an associated class.
  The kernel lets us install new classes into the inheritance hierarchy.
  The kernel lets us create objects (instances of classes)
  The kernel lets us call the methods of objects.

Fare:
 To be more general,
	* A class is a standardized interface to services.
	* The kernel IS exactly the mechanism that given an object and a class,
	 allows one to access the services for the object.
	* Those services may be extensions to an existing class' services.
	 That's "Inheritance".
	* More generally, one of those services may return another standard
	 interface, i.e. another "class". This exported class is embedded in
	 the first one.
	* A class may embed zero, one, or more other classes; it may even
	 embed the same class in different ways (e.g. a Double Queue can embed
	 a queue in one direction and a queue in the other).
	* Having classes and objects dynamically appearing in the system is
	 equivalent to our language being reflexive: you can write code from
	 inside the language; there is a class describing classes, and so on.


CHOICE OF LANGUAGE
------------------

WRITING OUR OWN LANGUAGE+PROGRAMMING ENVIRONMENT
------------------------------------------------
Prerequisite:
	* if the language appears to be the central step forward in MOOSE,
Status:
	proposed by Michael, 100% backed by me (Fare)
Idea:
	* we can even just design a language, a programming environment
	 and a shared library so that programs written in our language
	 would be nice and have all the facilities the OS should be
	 providing.
PROs:
	* by writing it on a common powerful platform (e.g. some Unix).
	* This implementation wouldn't need to worry about
	(e.g.) handling other languages and could be relatively portable.
CONs:
	* Using an existing platform means we do not control all the hardware
	 and particularly memory mapping and error catching.
	* It also means all kind of clumsiness while remapping MOOSE calls
	 into the host system calls, but that's the price to pay.
	* designing a language would take longer than learning an existing one.


*** If we decide that the language is not central to our project we should
*** try hard to use an existing language.

USING PLAIN "C"
---------------
Idea:	Write all the OS in plain "C"
Status:	no one supports it. I (Fare) am 100% against it.
PROs:	* We do not have to design or even learn a new language
	* C already exists and is widely available, and even quite "portable".
CONs:	* C's semantics are completely different from OO, parallel,
	 error-aware, persistent, annotated, specifiable, partial-evaluation
	 semantics.
	* Interfacing our C code in an such a way will be a pain in the
	 ass, while what are we going to interface it to ? Are we writing
	 an OS without client ?
	* If we stick to C's semantics, we are not likely to do better than
	 hUgeNIX.
	* Available "C"s are huge (see GCC).


USING CAML
----------
Idea:	* Write all the OS using "CAML-light"
	* CAML-light is a language based on typed lambda calculus, with
	 full support for side effects, and support for modules being
	 added.
	* Any CAML-light program is secure (but perhaps for memory
	 overflow ?) (unless you load code manually from disk...).
	* It works on any 32 or 64 bit Unix system, and even on 16-bit
	 DOS or with 32-bit DOS extender, as it's written in C and CAML.
	* See caml-light 0.6 on ftp.inria.fr

Status:	proposed by Fare, just in case it may interest someone
PROs:	* There are (small) doors to allow persistency (any object can be
	 saved on disk) and parallelism (there exist some multi-threading
	 patch somewhere), partial evaluation (though not lazy evaluation)
	 with lambda-calculus, etc.
	* Libraries to access system calls are available; you can link
	 (specially written) C code with CAML code. Interface to system
	 calls already exist.
	* Two CAML->C compilers exist, so the code may be efficient anyway.
CONs:	* CAML's OOness is very clumsy (currently being developped) at the
	 time.
	* Security is good, but may be VERY hard to enhance (or we may
	 add it in the CAML machine itself)
	* Annotating objects is possible, must be declared with the object.
	* CAML is far from the low-level.
	* CAML's semantic is good, but not exactly what we need, so either
	 we use plain CAML, and there's some inadaptation, or we write another
	 language on top of CAML, and that's somehow inefficient, or we take
	 CAML and modify it, but that's difficult.


USING SELF
----------
Status:	Proposed by Michael
PROs/CONs:	Can you send me your PRO's and CON's, please Michael ?
		What do current SELF implementation rely upon ?
		How does it match our requirements ?
		What does it look like ?
Michael's Suggestion:
	* Look at Self (OOPSLA '87, Sigplan 22:12 -- I think it's FTPable)
		Self is an OO language that uses a simpler alternative to
		inheritance.


Low level language tool used to implement the low level part of the OS:
======================================================================
Prerequisite:
	We're not already using a language on an existing platform.

Using TASM at first
-------------------
Prerequisite:
	if we happen to use the i386 as a basis on the assembly level;
	we write some important part of the system in assembly and/or we
	use a memory model other than pure flat memory model.
Idea:
	I think we can use TASM (Turbo Assembler, by Borland),
	and replace it later by our own integrated OO assembler library.
Status:
	first proposed, not yet contradicted; prerequisite in discussion.
PROs:
	* TASM is a powerful assembler for the lowest level part of MOOSE
	 on i386 (both real mode and protected mode), whose high-level
	 features are unique among existing low-level-able assemblers
	 (*arbitrary multiple segments*, powerful macros among which
	 I've written @IF @THEN @ELSE @ENDIF, Print "hello", for runtime,
	 etc).
	* If we can skip its features hopefully, we can replace it by as86
	 for real mode and gas for protected mode (flat model only). but I
	 don't think this is much feasible, unless the assembly part is
	 minimal, which surely means we use an existing language with its
	 own memory management (which surely is not easy to use in a
	 secure multithreading way).
CONs:
	* MASM (Microsoft Macro assembler) may be more used among us, and
	 as TASM has a MASM-compatible mode, we may prefer to use MASM.
	* The main problem is it's commercial software. That it runs under
	 DOS should not be a problem. It's real-mode only (at least for older
	 versions) with no direct I/O, so should work under any DOS emulator.

A FORTH-like thing
------------------
Idea:	* Use a (32 bit)word-aligned direct threaded language as a basis. This
	 reduces underlying hardware dependencies and need for a powerful
	 assembler (or even for an assembler at all, outside quick interrupt
	 driven I/O loops).
Status:	* first proposed, not yet contradicted.
PROs:	* It's quick and cheap to write, easily extensible, and nobody
	 forbids writing a compiler that'll produce machine code from our
	 language later.
	* The threaded code can point to "C" void(void) code or code written
	 in any language (use of global variables as the machine' state).
	* We're not stuck with C's limited semantics as of parallel
	 programming & error recovery, etc.
CONs:	* Speed may be reduced as compared as using a existing "optimizing"
	 compiler for a common language (e.g. GCC).


Using "C"
---------
Idea:	* Implementing the language completely in C.
Status:	* Put there so that we do not forget any solution.
PROs:	* The produced code is somehow faster than if using threaded code.
CONs:	* difficult to maintain, port, or retranslate in our
	language as C's semantics is so different from our own.
	* the threaded code may be more usable afterwards, and we
	 may compile it one day, whereas all effort put in C will
	 be lost.

