The Artima Developer Community
Sponsored Link

Weblogs Forum
Can Contracts be Equated with Types?

38 replies on 1 page. Most recent reply: Aug 18, 2006 3:45 AM by Achilleas Margaritis

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 38 replies on 1 page
Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Can Contracts be Equated with Types? (View in Weblogs)
Posted: Aug 5, 2006 1:11 PM
Reply to this message Reply
Summary
I am wondering out loud whether a contract can be completely expressed as a type (or type class) in a language with a sufficiently advanced type system.
Advertisement
There are clear parallels between types and contracts. For instance, an unsigned integer can be viewed as an integer which maintains the invariant of always being greater than or equal to zero. The only substantial difference I can think of is that types are usually resolved entirely at compile-time while contracts often have assertions that can only be resolved at run-time.

The question that I am pondering is whether I can bridge the two by adding type-safe casting operations to the definitions of types. Perhaps by using some form of type-class, or concept.

Consider the following function grow_list which takes a list and appends an element to it a specified number of times:

define grow_list : (a:list x:value n:uint) -> (b:list)
{
  [[dup [append] dip] dip dec] [dup neqz] while pop pop
}
(note: this is not yet implemented on the Cat compiler!)

If the implementation is meaningless to you, it isn't very important, but it is pretty much the same as Joy.

The question is, should I express the postcondition as part of the type expression? The postcondition can be expressed in pseudo-code:

[{ b size } { a size n + } eq]
Note that you can name arguments for the purpose of type expressions, but not as part of the implementation. The curly braces have actually no meaning, and are simply there to help clarify the structure of the program. So there are two questions here:
  1. should the type system capture postconditions and other constraints
  2. if so then what should the mechanism be for expressing constraints?
I am currently of the feeling that behavioral constraints should be expressed in the type system. I am playing with the current ad-hoc notation:
define grow_list : (a:list x:any n:int)->(b:list) 
  <: [{ b size } { a size n + } eq]
{
   ...
}
Anyway, this is as far as I've managed to get so far today. I'd appreciate any opinions shared on the issues presented.


Adi Shavit

Posts: 6
Nickname: adish
Registered: Apr, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 6, 2006 12:51 AM
Reply to this message Reply
Amazing! I was thinking about the same thing in my car this morning!

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 6, 2006 3:15 AM
Reply to this message Reply
If you expand the type system more you'll see that you're writing the implementation twice: (a) in the type signature (b) in the body of the procedure. What if you want to express (in the type system) that the appended items are in fact x? You're writing the same thing twice (only in another language).

Therefore I think this isn't good. A type system is good if it adds functionality like polymorphism.

Type-safe casting:

str->int :: (str) -> (int)
int->str :: (int) -> (str)


or:

to-str :: (any) -> (str)

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Can Contracts be Equated with Types? Posted: Aug 6, 2006 9:38 AM
Reply to this message Reply
> If you expand the type system more you'll see that you're
> writing the implementation twice: (a) in the type
> signature (b) in the body of the procedure. What if you
> want to express (in the type system) that the appended
> items are in fact x? You're writing the same thing twice
> (only in another language).

Do you mean that the constraints can be used to completely express the solution to problem, ala constraint based programming?

This would definitely be interesting. For trivial programs I agree, but for non-trivial programs I am not sure that the preconditions and postconditions can completely express the implementation. I am not saying that you aren't right though.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: Can Contracts be Equated with Types? Posted: Aug 6, 2006 7:10 PM
Reply to this message Reply
There is a whole field of study 'dependent types':

http://en.wikipedia.org/wiki/Dependent_types
http://www.e-pig.org/downloads/ydtm.pdf

special languages, e.g.:

http://en.wikipedia.org/wiki/Epigram_programming_language

and associated conferences, e.g.:

http://www.cs.nott.ac.uk/types06/

That attempt to do exactly this; express all the constraints of a program in the type system.

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Can Contracts be Equated with Types? Posted: Aug 7, 2006 12:57 AM
Reply to this message Reply
> ...an unsigned integer can be viewed as an integer
> which maintains the invariant of always being greater than zero.

Perhaps you'd better update Wikipedia (et al.). They seem to think unsigned integers can include the value zero
(http://en.wikipedia.org/wiki/Integer_%28computer_science%29).

Alex Stojan

Posts: 95
Nickname: alexstojan
Registered: Jun, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 7, 2006 5:18 PM
Reply to this message Reply
> Perhaps you'd better update Wikipedia (et al.). They seem
> to think unsigned integers can include the value zero
> (http://en.wikipedia.org/wiki/Integer_%28computer_science%2
> 9).

The text says "... greater than or equal to zero".

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Can Contracts be Equated with Types? Posted: Aug 7, 2006 7:01 PM
Reply to this message Reply
> > Perhaps you'd better update Wikipedia (et al.). They
> seem
> > to think unsigned integers can include the value zero
> >
> (http://en.wikipedia.org/wiki/Integer_%28computer_science%2
>
> > 9).
>
> The text says "... greater than or equal to zero".

I changed it after Vincent pointed out the mistake/

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 8, 2006 5:06 AM
Reply to this message Reply
Chris,

the provability of a type system is limited by the nature of the Turing machine. The halting problem proves that any algorithmic system can not be proven to terminate, and therefore a depentent type system is undecidable for all cases.

A contracts system equals a type system where types are values, i.e. a depentent type system.

A dependent type system is the only kind of type system that can catch logical errors in the code. It is precisely the lack of this that makes our programs have logical bugs.

Of course, there is room for improvement. If you remember, I have sent you an e-mail about how to make contracts statically proven in most cases (you did not reply to me; didn't you get the e-mail?). I would be more than happy to send you again the e-mail, if you wish.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 8, 2006 2:12 PM
Reply to this message Reply
Could you post the email here? I'm sure I'd find it very interesting!

Eelis van der Weegen

Posts: 2
Nickname: eelis
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 8, 2006 4:53 PM
Reply to this message Reply
> Chris,
>
> the provability of a type system is limited by the nature
> of the Turing machine. The halting problem proves that any
> algorithmic system can not be proven to terminate, and
> therefore a depentent type system is undecidable for all
> cases.

"Any algorithmic system" is a LOT broader than just Turing machines. There are various interesting (and useful!) algorithmic systems that are not Turing complete.

For the issue at hand, I present Coq's [1] Calculus Of Inductive Constructions (CIC) as a counterexample to your claim that dependent type systems are inherently undecideable. The CIC includes a type system that supports dependent types, and yet type checking in the CIC is decideable.

It is true that type-checking in a type system with dependent types may involve execution of arbitrary algorithms in that system. And if that system is Turing Complete, then yes, it becomes undecideable. However, the CIC is not Turing complete.

In the CIC, one can only write algorithms that terminate. For example, when one wants to do recursion (which is the only way to "loop" in the CIC), one is obligated to formally prove (in the same logical system) that the recursion will eventually terminate.

Fortunately, the vast majority of interesting algorithms can be proven to eventually terminate, so a lot of interesting algorithms (and other math) can be formalized in Coq, despite the lack of Turing-completeness.

Turing-completeness is overrated. ;-)

[1] Coq - http://coq.inria.fr/

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Can Contracts be Equated with Types? Posted: Aug 8, 2006 10:53 PM
Reply to this message Reply
> Of course, there is room for improvement. If you remember,
> I have sent you an e-mail about how to make contracts
> statically proven in most cases (you did not reply to me;
> didn't you get the e-mail?).

I did reply on March 21st:

Hi Achilleas,

I'm sorry it took me so long to get back to you. This new job has me swamped. I've looked at your idea, and it does seem solid for languages without side-effects (for example Unimperative, or Joy or Haskell). For languages with side-effects, then I don't see how we can practically measure the output of a function (since it can affect any part of the state). I hope this makes some sense. I think your idea merits further exploration in the context of smaller, easier to study languages. I do think that LtU would have some good feedback. If you are nervous about sharing your ideas, I suggest to start by asking questions to find out about related work. There is a possibility this idea is currently being researched. However, it definitely makes me think about what could be done applying your idea to Unimperative. Keep coming up with good ideas!

Christopher

> I would be more than happy to
> send you again the e-mail, if you wish.

I encourage you to post it here!

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Can Contracts be Equated with Types? Posted: Aug 8, 2006 10:56 PM
Reply to this message Reply
> Turing-completeness is overrated. ;-)

Good point. Thanks for sharing that post!

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 9, 2006 1:32 AM
Reply to this message Reply
> I did reply on March 21st:
>
> Hi Achilleas,
>
> I'm sorry it took me so long to get back to you. This new
> job has me swamped. I've looked at your idea, and it does
> seem solid for languages without side-effects (for example
> Unimperative, or Joy or Haskell). For languages with
> side-effects, then I don't see how we can practically
> measure the output of a function (since it can affect any
> part of the state). I hope this makes some sense. I think
> your idea merits further exploration in the context of
> smaller, easier to study languages. I do think that LtU
> would have some good feedback. If you are nervous about
> sharing your ideas, I suggest to start by asking questions
> to find out about related work. There is a possibility
> this idea is currently being researched. However, it
> definitely makes me think about what could be done
> applying your idea to Unimperative. Keep coming up with
> good ideas!
>
> Christopher
>
> > I would be more than happy to
> > send you again the e-mail, if you wish.
>
> I encourage you to post it here!

Ah, ok. Somehow I did not get hold of it.

I disagree that it can not be applied to languages without referential transparency.

I won't be posting these ideas to LtU, because I am too lazy to formalize them. If anyone is interested, feel free to pick up the idea and make a formal paper out of it.

Anyway, for anyone interested, the idea is:

A block of code has a set of inputs (allowed values) and outputs (possible outcomes). When two blocks of code are paired up in a sequence, the outputs of the 1st block must be a subset of the inputs of the 2nd block. A compiler rejects a block of code that does not conform to this simple rule. This technique could enable static contract evaluation.

The set of inputs can be precisely defined by declaring contracts.

In order to implement this, sets should be smartly represented, either as sets of discrete values, or ranges, or intersections/unions. You do not have to perform big computations, because the I/O sets are small usually.

The real interesting trick in this technique is that when two blocks of code are combined, new sets of inputs and outputs are created for the combined block, which does not necessarily include the values of the two blocks that where combined.

The above does not relate to the halting problem in anyway. It does not tell you if an algorithm terminates or not; it is a mechanism for checking contracts at compile-time, instead of run-time.

I am optimistic about this technique that it can even tell you if some algorithms loop forever, by treating the Program Counter as an input/output value.

The input/output information can be kept around in libraries, so as that when one uses the library, the contracts are part of the system.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 9, 2006 12:04 PM
Reply to this message Reply
This sounds interesting. Do you have any ideas about recursion?

For example:

f = a b [f] if

How do you make sure that the output of f is correct if it depends on f itself (and maybe on the correctness of f)?

Vladimir Nesov

Posts: 27
Nickname: robotact
Registered: Aug, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 2:33 AM
Reply to this message Reply
> Anyway, for anyone interested, the idea is:
>
> A block of code has a set of inputs (allowed values) and
> outputs (possible outcomes). When two blocks of code are
> paired up in a sequence, the outputs of the 1st block must
> be a subset of the inputs of the 2nd block. A compiler
> rejects a block of code that does not conform to this
> simple rule. This technique could enable static contract
> evaluation.

How can such input and output be defined/determined? There should be powerful abstraction on what input/output is to make such thing robust. Anyway it's basically what all static analyzers are trying to do, and all ruminations are around what is appropriate approximation of input/output (data flow).

Or is the point is that one doesn't need to determine data flow to check this property? But for procedure calls one needs to compare effects of called procedures, and it seems to require some sort of data flow.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 5:48 AM
Reply to this message Reply
> This sounds interesting. Do you have any ideas about
> recursion?
>
> For example:
>
> f = a b [f] if
>
> How do you make sure that the output of f is correct if it
> depends on f itself (and maybe on the correctness of f)?

Let's see the factorial function (written analytically). The contract is that the input is greater than 0:


1 int fact(int n : n >= 0) {
2 int result;
3
4 if (n == 0) {
5 result = 1;
6 }
7 else {
8 int n1 = n - 1;
9 int f = fact(n1);
10 result = n * f;
11 }
12 return result;
13 }


Here is the analysis:


Line Input Output
------------------------------------------
1 n(int) n(0 | pos int)
4 n(0 | pos int) n(0)
5 n(0) result(1)
8 n(pos int) n1(0..n-1)
9 n1(0..n-1) f(pos int)
10 n(pos int), f(pos int) result(pos int)
12 result(1, pos int) result(pos int)


Explanation:

line 1 : the input number must be greater than or equal to zero. Therefore, for the rest of the block, it is considered so.

line 4 : the static if n == 0 makes sure n is 0 inside the then block.

line 5 : the result is 1.

line 8 : since line 4 is executed only if n == 0, it means n is a positive integer, not zero, for lines 8-10. Therefore, n1 is >= 0 due to the subtraction with 1.

line 9 : n1 is a legal value for passing it to 'fact', because n1 >= 0. Since n1 is a subset of n, the end result is 1 (already computed), so f can only be a positive number.

line 10 : the result of the multiplication is a positive integer, since both n and f are >= 1.

line 12 : the result is either 1 or a positive integer i.e. the result is >= 1.

I am sure there are some holes in the above, I am no mathematician...but I guess whatever abstraction can I do with my brain, I can pass it to the computer, provided that it is formed correctly.

Vladimir Nesov

Posts: 27
Nickname: robotact
Registered: Aug, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 6:39 AM
Reply to this message Reply
Problem is that if constraint is any complex, you'd need to force it at least local inside the method, analyser wouldn't be able to check that forced annotation is indeed correct. Though creating practical solution on at least this level would be great by itself.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 8:12 AM
Reply to this message Reply
> line 9 : n1 is a legal value for passing it to 'fact',
> because n1 >= 0. Since n1 is a subset of n, the end result
> is 1 (already computed), so f can only be a positive
> number.

Do you have any ideas about the implementation of this, specifically this:

"the end result is 1 (already computed), so f can only be a positive number."

I have no idea how to implement this reasoning in a computer program. The compiler has to prove that for every call to fact the end result will be 1. So if you subtract 1 from n you'll reach the base case eventually.

Do you think it's possible to prove this in more complex cases? To me this sounds like the halting problem...

Vladimir Nesov

Posts: 27
Nickname: robotact
Registered: Aug, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 10:32 AM
Reply to this message Reply
This particular problem can be estimated well, you'd need to apply "widening" in loop junction points, in this case recursion creates a loop. After several iterations (result of first is that return value of fact() is 1, result of second is that it's in interval [1,2], etc.) one can extrapolate changes, extending initial value 1 in direction of change, obtaining [1,+inf) in result. Few iterations after that are likely to impose possible upper constraints.

Problems begin from simpliest C construction such as char buf[1000];
...
for(int i=0;buf[i]!=0;++i) ...
It can be handled using some heuristics, but it's just an example, custom construction will create such obstacles again and again. One can create for_each function which by its contract guarantees that collection is traversed correctly, but such assumbtion will need to be expressed explicitly without checker being able to check if it's really so for some complex combination of custom container implementation and access to the same container within the loop.

Another problem is ubiquitous aliases. Alias analysis problem is yet to be solved, and propagation of annotations associated with values seems to inevitably require alias information.

Eelis van der Weegen

Posts: 2
Nickname: eelis
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 11:28 AM
Reply to this message Reply
I'd like to make two points:

First, it's possible to reason about the input/output correctness of algorithms, at least in systems that were designed for this purpose. To illustrate this point, I will prove the >0 output guarantee of the factorial function in one such system, namely Coq (the same one I mentioned before).

First, we define factorial in a straightforward way:

Fixpoint fact (n: nat): nat :=
match n with
| 0 => 1
| S m => (fact m) * n
end.

(nat is the type of natural numbers.)
Next, we formally prove the >0 guarantee in an accompanying lemma:

Lemma fact_result: forall n, (fact n) > 0.
unfold gt.
induction n.
simpl.
apply lt_n_Sn.
simpl.
replace 0 with (0 * fact n).
replace (fact n * S n) with (S n * fact n).
apply mult_lt_compat_r.
apply lt_O_Sn.
assumption.
rewrite mult_comm.
reflexivity.
reflexivity.
Qed.

The proof is pretty unreadable in this form unless one has experience proving things in Coq, but the essence is just proof by induction on n.

The second point I'd like to make is that if the type system is expressive enough, these input/output guarantees can be expressed as types (rather than as accompanying lemma's), exactly like the opening poster theorized.

In Coq, functions whose input/output types incorporate pre- and postconditions are called strongly specified, as opposed to weakly specified functions whose input/output types do not. The fact definition above is an example of a weakly specified function. To illustrate the difference, here's a strongly specified version of fact:

Lemma one_gt_zero: 1 > 0.
unfold gt.
apply lt_n_Sn.
Qed.

Lemma rec_call_valid (rec_val n: nat) (rec_spec: rec_val > 0): (rec_val * S n) > 0.
unfold gt.
intros.
rewrite mult_comm.
replace 0 with (0 * rec_val).
apply mult_lt_compat_r.
apply lt_O_Sn.
assumption.
reflexivity.
Qed.

Fixpoint fact_strong (n: nat): { r: nat | r > 0 } :=
match n with
| 0 => exist _ 1 one_gt_zero
| S m => let (rec_val, rec_spec) := (fact_strong m) in
exist _ (rec_val * (S n)) (rec_call_valid _ _ rec_spec)
end.

The details of what's going on here are unfortunately more complex and involve some Coq specifics, so I won't go into them. The key point however is that the return type has changed from plain nat to { r: nat | r > 0 }, which is a pair-like (and dependent) type consisting of a nat and a proof that said nat is greater than 0. The definition of fact_strong uses the two smaller lemmas (which are now merely implementation details) to produce the result value and the >0 proof simultaneously.

These examples really only show the tip of the iceberg of what's possible. The research field that studies the various interesting relations between type systems, logic, proofs, algorithms, and correctness, is called Type Theory. Before I was introduced to Type Theory, I pretty much had the same gut-feeling as the opening poster about the potential of type systems, and learning about Type Theory was an incredible eye-opener for me.

Unfortunately, all of the above is currently somewhat acedemic; the type systems and formality of semantics of conventional/mainstream programming languages are not nearly expressive or "pure" enough to be able to effectively express let alone prove nontrivial properties of programs written in them.

That said, most programmers probably can't be bothered with all this proving business anyway, although that may be somewhat of a defeatist attitude ;-).

Vladimir Nesov

Posts: 27
Nickname: robotact
Registered: Aug, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 10, 2006 12:02 PM
Reply to this message Reply
Eelis van der Weegen
I'll look into this field.
How do you assess proof expenses, that is time required to develop proved code (at least properties which guarantee no buffer overflows, resource leaks, etc. common stuff) vs. time to develop unproved code (maybe with tests) for some usual code portion which is a part of not-small system?

Andrei Korostelev

Posts: 5
Nickname: andreika
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 12, 2006 4:42 AM
Reply to this message Reply
Contracts have semantic nature, i.e. bahavior.
Types have syntactic nature.

It is clear that possibilities to express behavior only in terms of traditional type compatibility are very limited.

The question whether the type system need to support behaviour compatilbility depends on the abstraction level.

For example SOA-based systems rely on behavior compatibility between services, whereas C++ language(as an example) used to implement these services relies on a static type system to provide maximum performance.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 12, 2006 4:48 AM
Reply to this message Reply
Types also have a semantic nature. Overloading for example, is built on top of types.

Andrei Korostelev

Posts: 5
Nickname: andreika
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 12, 2006 1:37 PM
Reply to this message Reply
Overloading has compile-time resolution, whereas bindings built on top of contracts are resolved at run-time.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 13, 2006 3:00 AM
Reply to this message Reply
True, but what is your point?

Syntax = semantics.

You can have contracts in a turing complete language that doesn't support them natively. They just have a different syntax.

Andrei Korostelev

Posts: 5
Nickname: andreika
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 13, 2006 10:22 AM
Reply to this message Reply
My point is that modelling behavior in terms of traditional type compatibility is often not enough to catch runtime semantics of component/service contracts.

Here I to refer the idea expressed by Rockford Lhotka in his "A SOA Versioning CovenantA SOA Versioning CovenantA SOA Versioning Covenant" article, http://www.theserverside.net/tt/articles/showarticle.tss?id=SOAVersioningCovenant

In this article he made a distinction between semantic contracts, which is "the definition of an API or a message schema in terms of data types and method signatures" and semantics contracts, which indeed model behavior. The idea was that building systems basing on services semantic contracts, as opposite to syntactic conmtracts, increases flexibility of such systems.

Andrei Korostelev

Posts: 5
Nickname: andreika
Registered: Aug, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 14, 2006 12:42 AM
Reply to this message Reply
Correction for the last paragraph:
...distinction between syntactic contracts and semantic contracts

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Wonderful Posted: Aug 15, 2006 8:30 AM
Reply to this message Reply
I honestly thought things had petered out here, so I was sad my wisdom would be missed (g). So I'm glad people have kept the flame alive.

One of the fundamental bits of advice I got from The C++ Programming Language is that "classes should have a clear invariant." By feeding data to a class, you get objects. The class should make sure, at all times, that the data in an object meets that invariant. Maybe through sanity checks, maybe through constraints, maybe through the type system or something else.

Thinking of strong typing as a way to catch type errors at compile time instead of runtime isn't all that interesting to me. But thinking of strong typing as a way to implement Programming With Contracts, through class invariants and type conversions, is interesting to me.

Consider:

template<typename T> locked
{
  T& locked_info;
 
public:
  locked(T& data) : locked_info(data)
  { /* yes, I'm locking *after* I've initialized, but before use; it's safe because I won't get that lock (and won't use the data) until any other locks on this data have been released -- meaning the data *should be* updated properly at that time. */
    lock(locked_info);
  };
 
  operator T&()
  {
    return locked_info;
  };
 
  ~locked()
  {
    unlock(locked_info);
  };
};
 
int add_two_locked(locked<int> x)
{
  return x += 2;
};
 
int main()
{
  int y = 3;
  add_two_locked(y);
};


What's the invariant for locked? That while the object is in existence, locked_info will be protected by a recursive read-write lock.

Now, yes, there are problems there. If you actually pass a locked<int> to add_two_locked, the compiler-generated copy constructor won't properly lock the temporary created, but the destructor will be called and unlock it (for proof, change the lines "lock(locked_info);" and "unlock(locked_info);" with "std::cout << "locked/unlocked " << this << '\n';" and see what happens).

Oh, and IIRC, the order evaluation of arguments passed to functions isn't guaranteed to follow any set pattern, meaning that you run the risk of deadlocks because you can't promise that object A will be locked before object B for a function T add_x(locked<T> A, locked<T> B). Especially if you don't pass them in the same order every time you call two-argument functions.

But the concept is interesting.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

formatting Posted: Aug 15, 2006 8:31 AM
Reply to this message Reply
Oops. Sorry. I thought there was word-wrap on long code comments.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 15, 2006 8:42 AM
Reply to this message Reply
> > line 9 : n1 is a legal value for passing it to 'fact',
> > because n1 >= 0. Since n1 is a subset of n, the end
> result
> > is 1 (already computed), so f can only be a positive
> > number.
>
> Do you have any ideas about the implementation of this,
> specifically this:
>
> "the end result is 1 (already computed), so f can only be
> a positive number."
>
> I have no idea how to implement this reasoning in a
> computer program. The compiler has to prove that for every
> call to fact the end result will be 1. So if you subtract
> 1 from n you'll reach the base case eventually.
>
> Do you think it's possible to prove this in more complex
> cases? To me this sounds like the halting problem...

Maybe a solution is to do it more like humans do, i.e. ignore the recursion, examine the code after the recursive point, extract the possible values from the operations, then go back and examine the recursive point with the new information at hand.

For example, one could say that:

1) after the recursive point, we have a multiplication.
2) we know 'n' is always positive in the recursive part.
3) we know the non-recursive path produces the value 1.
4) a multiplication of positive number to 1 produces another positive number.
5) the next step multiplies this positive number with N, which is another positive number.
6) therefore the result is a positive number.

Of course encoding the above in mathematical formulas may be impossible (I am only speculating here).

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 15, 2006 11:59 AM
Reply to this message Reply
I think it's possible to prove it. If you can prove that the recursion will always hit the base case you're done. You can prove that n will get closer to the base case. That's pretty easy to prove. But if you evaluate fact(4.5) it won't stop. You don't have this problem in this case because the function only accepts integers, but there might be a similar problem with other functions (where the base case will be "skipped").

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 16, 2006 2:13 AM
Reply to this message Reply
> I think it's possible to prove it. If you can prove that
> the recursion will always hit the base case you're done.
> You can prove that n will get closer to the base case.
> That's pretty easy to prove. But if you evaluate fact(4.5)
> it won't stop. You don't have this problem in this case
> because the function only accepts integers, but there
> might be a similar problem with other functions (where the
> base case will be "skipped").

Let's say the integer constraint is relaxed and it is possible to do 'fact(4.5)'; Maybe it is not that difficult to prove 'infinite' recursion in this case, because the value '0' will never be produced by the subtraction n - 1. If the initial input is 4.5, then subsequent inputs will be 3.5, 2.5 ... 0.5, -0.5 etc.

Maybe algorithms can be classified into two categories: 1) those that recursion always hits the base case (as you've stated) 2) those that we can't prove recursion will always hit the base case. The presented approach might be useful for identifying and proving the correctness of computational problems of category 1, and also offer insights into category 2.

Anyway, I think that contracts can be equated with types, provided that it is possible to transfer all the assumptions we have in our brains to the computer.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 16, 2006 11:06 AM
Reply to this message Reply
Types are a subset of contracts?

It would be nice if we could develop a general algorithm that determines the category (1 or 2) of a function.

Let's examine the map procedure:

map(fn,x:list) = cons(fn(car(x)), map(fn, cdr(x)))
map(fn,nil) = nil


lst should be nil for the process to stop, so cdr(x) should return nil for some value of x. If you apply cdr repeatedly: cdr(cdr(... lst ...)) it will produce nil (if you don't have circular lists).

It would be nice if the compiler can check this in the same way as fact(): with numbers. If you keep subtracting 1 from an integer n it will produce 0.

The definition of length:

length(x:list) = length(cdr(x)) + 1
length(nil) = 0


From this the compiler should be able to use the same reasoning as is needed for fact(). Of course, if fn loops forever, map will never return either...

; counts the leaves of a tree
; count-leaves('(2 3 (5 5) 4)) => 5
 
count-leaves(x:pair) = count-leaves(car(x)) + count-leaves(cdr(x))
count-leaves(nil) = 0
count-leaves(x:any) = 1


How can the compiler prove that this function is correct?

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 17, 2006 3:46 AM
Reply to this message Reply
> From this the compiler should be able to use the same
> reasoning as is needed for fact(). Of course, if fn loops
> forever, map will never return either...
>
>
> ; counts the leaves of a tree
> ; count-leaves('(2 3 (5 5) 4)) => 5
> 
> count-leaves(x:pair) = count-leaves(car(x)) +
> count-leaves(cdr(x))
> count-leaves(nil) = 0
> count-leaves(x:any) = 1

>
> How can the compiler prove that this function is correct?

What exactly do we wish to prove for the count-leaves function?

From what I can see, there are no contracts for that function other than the types used.

Same goes for function length or map.

Jules Jacobs

Posts: 119
Nickname: jules2
Registered: Mar, 2006

Re: Can Contracts be Equated with Types? Posted: Aug 17, 2006 8:16 AM
Reply to this message Reply
Could you write the contracts for these functions? I'd like to prove that the recursion will stop if you don't have circular lists/trees.

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 17, 2006 12:54 PM
Reply to this message Reply
The proof would revolve around the line:

count-leaves(x:pair) = count-leaves(car(x)) + count-leaves(cdr(x))

cdr can only be called on a list, which has the contract of having a positive numer of elements or being empty, and makes the list shorter by 1 element. Provided that nothing is adding to that list (which it isn't here), you will eventually get to an empty list.

Returning to the "contracts == types?" question, the type for list provides this contract, and the programmer can expect that lists conforming to this contract (that is, cdr returns a list with one less item) will always work in this function.

If you were chasing pointers in the list, you could end up with a cyclic graph, which would make it possible to hit infinite recursion. However, the contract for a list says nothing about whether the items in that list refer to each other. You'd need another contract, and potentially another type. Say, a type that guarantees information about all objects of type X are kept in a hash map that can be used to tell if something's been visited. Like a Perl "inside out class."

Max Lybbert

Posts: 314
Nickname: mlybbert
Registered: Apr, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 17, 2006 1:09 PM
Reply to this message Reply
Wait, unless you were wondering if the function would properly descend into lists inside that list. I keep studying Lisp, and I remember this is a problem, but I can't remember what the proper fix is.

Anyhow, if that's the case, then cdr doesn't provide the contract your lookig for. Or at least, it may not.

Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Can Contracts be Equated with Types? Posted: Aug 18, 2006 3:45 AM
Reply to this message Reply
> Could you write the contracts for these functions? I'd
> like to prove that the recursion will stop if you don't
> have circular lists/trees.

First approach:

int count_leaves(l) {
    ensure(l does not belong in set of values referenced by l);
    if (l == null) return 0;
    if (l is not a list) return 1;
    return count_leaves(l) + count_leaves(next(l));
}


Obviously the above can not be proven stand-alone, but if put in context, then it might work. For example:

1 List l = new List;
2 append(l, l);
3 int c = count_leaves(l); 


If we analyse the sets of values for the above code:

line 1: l = {nil}
line 2: l = {l, nil}
line 3: error; we see that the set of values of l contains itself.

Second approach:

Non-cyclic referencing could be proved by forbidding operations where the inserted element does not appear anywhere as the target list.

This second approach is similar to how humans operate: we form a collection of associations between variables, and then we search the code for list insertions where the inserted element does not appear in the collection of associations (at least that's what I do! :-)).

So, for example, if we have 3 lists A, B and C, and B was a member of A and C was a member of B, then we could see that it would be illegal to insert A into C, due to the following associations: A -> B -> C -> A.

Again, the issue here is how to represent the information/abstractions we have in our heads.

Flat View: This topic has 38 replies on 1 page
Topic: Can Contracts be Equated with Types? Previous Topic   Next Topic Topic: Are Web Services Real? Part II

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use