Specifications

Laurent Martelli martelli@iie.cnam.fr
02 May 1999 00:44:57 +0200


>>>>> "Tril" == Tril  <dem@tunes.org> writes:

  Tril> On 1 May 1999, Laurent Martelli wrote:

  >> "If the object disappears then your unique ID is useless. And, if
  >> you allow anyone to access an object if they know its ID, your
  >> system won't be very secure"
  >> 
  >> You say that the 1st issue can be tackled with a "two-way
  >> reference" so that references can be invalidated when the object
  >> is destroyed. Well why not. But what does it mean "to invalidate"
  >> references to an object ? We could very well do a runtime
  >> checking and see if the object referenced exists when we want to
  >> use it. And what about garbage collection ?

  Tril> The problem with checking if it exists, is that if it doesn't
  Tril> exist, some other object may have taken its ID. (Then you may
  Tril> mistakenly think it exists because the ID is in use)
  Tril> Therefore, we can't allow an object to be deleted until all
  Tril> references to it are gone.  By invalidation, I meant that the
  Tril> reference is actually deleted.  (Taken out of use, and queued
  Tril> for deletion, marked for GC, whatever)

  Tril> I'm not a GC person, but I guess you could have the reference
  Tril> marked for deletion, then the ID would be still in use until
  Tril> actual GC took place.  Maybe a new object could get the ID
  Tril> while it's still waiting to be erased, and the new object
  Tril> would be created at the same time as the other one is deleted,
  Tril> making some delayed creation available?

It could also be specified that one IDs cannot be reused. In fact I
find it strange that IDs could be reused, given the definition of
IDs. I would even go further and say that objects cannot be
destroyed, given that objects are pieces of information. Information
is not created and then destroyed. You just use it sometimes, and some
other times you don't care about it. But I really don't like the idea
that you could destroy them. I often like to take the example of
numbers, say integers. They've always existed, and they will always
exist, and it makes no sense to me to create an integer or destroy
it. And it also make no sense to have to objects that are the same
number. Now I'm not sure if all objects should obey this law.

  >> You solve the security problem by saying that the client will not
  >> be allowed to read the reference. By what can you do with it then
  >> ?

  Tril> It can use the reference to do any legal operation on the
  Tril> object.  It just can't find the ID for the object.

I guess that legal operations include comparing two IDs. And it means
that you can read them somehow, even if you don't know how they are
implemented. 

  >> o Functions and Types
  >> 
  >> I agree that one argument is all you need. But I think that
  >> specifying a function only by its input and output type is a poor
  >> specification. In fact, I think of typing as a special case of
  >> pre/post conditions. If you allow any function to be used in the
  >> pre/post conditions, they can be arbitrarily complex, and you can
  >> fully specify what the function does (you don't need an
  >> implementation since it is contained in the post
  >> condition). Let's take an example :
  >> 
  >> if you have a function `F' which takes an integer and returns an
  >> integer, you don't know what it does. But if you say that the
  >> pre-condition is that the argument is an integer, and that the
  >> post-condition is that the result is such that `result = argument
  >> + 1' you have a _full_ specification of F, and there's no need to
  >> implement it.

  Tril> I completely agree with this method.  But I don't distinguish
  Tril> between typing and pre/post conditions.  They're the same,
  Tril> therefore the full specification of F is that it maps from the
  Tril> "integer" type to the "incremented integer" type.  Types are
  Tril> formed by conditions as you said, and I do allow any function
  Tril> to be used as the condition.

  Tril> If we do this universally, functions are simply links between
  Tril> two types.  All the information is in the type, and functions
  Tril> can be automatically generated.  You won't have to explicitly
  Tril> USE a function, much less give it a name "F".  Just select two
  Tril> types, and draw an "arrow" <grin> between them.  The system
  Tril> does the rest.

I can't see how this could apply to the "f(x)=x+1" example. The
domain and the codomain are the same, and linking Z with Z does not
fully specify the function. So it seems that it's not enough to link
two types, given the definition of type that you give.

By the way, I don't like talking about "automated code generation". 
I'd rather say "interpretation of specifications", which can be
implemented by generating code in another language, and then
interpreting this generated code. Anyway, it always end with
interpretation of some code, even if the interpreter it the CPU. 

  Tril> (Heavy use of this method would mean a LOT of types.  So in
  Tril> any program, you will probably define a lot of types on the
  Tril> fly while the program is running, instead of having a static
  Tril> group of predefined types.)

  >> o Subtypes and Supertypes
  >> 
  >> Sets and subsets are one way to see things. But I believe that a
  >> behavioral understanding of the subject can also be very
  >> useful. Knowing that an object is part of a set of objects does
  >> not tell much about it. What you usually want to know is what you
  >> can do woth it, ie how it behaves. Have you read Liskov's papers
  >> about behaviour and inheritance ? (I don"t have pointer, and my
  >> ISP is down, sorry :-( ) It seems to me that the behavioral
  >> definition of types and subtypes is the only one which makes
  >> sense.

  Tril> You posted it before, I found in the archives:
  Tril> http://www.cs.cmu.edu/afs/cs/project/venari/www/subtype-toplas.html

  Tril> Knowing an object is part of a set (defined by a condition
  Tril> being true) DOES tell a lot about it because the set is
  Tril> directly used as the domain of functions.  You can determine
  Tril> all the functions that use a type (because the way they "use"
  Tril> the type is by linking to it, and these are one example of two
  Tril> way links), and then you DO know what the object can do.  This
  Tril> is basically the reason for types.  How is my notion different
  Tril> from behavioral?  (I haven't read the paper, I will soon and
  Tril> post a commentary)

I had not thought of it this way. It looks like you are describing
types by their real use rather than by their intended use. It looks
like dynamic typing à la smalltalk, where different classes can
implement the same message, and you don't really care about the actual
class of an object as long as it accepts the message that you send to
it. But smalltalk's definition of a message is poor since it is only
based on the name of the selector, and not on it's semantic. 

  >> o Generic Functions
  >> 
  >> Since this paragraph is based on your definition of types and I
  >> don't agree with it, I don't agree with that one too :-)
  >> Especially when you say that a generic function "is a function
  >> with no definition of its own, but delegates to other
  >> functions". In fact this what all functions do. But the
  >> dispatching algorithm vary. If you think about it, all functions
  >> end up calling other functions (or themselves).

  Tril> Yes, all functions delegate, and that's just another reason
  Tril> why generic functions aren't much different from regular
  Tril> functions. 

That's why I think it's no use to talk about them in the
specifications. But it could be an interesting design patern. 

Laurent