|
Re: The Concept of Concepts
|
Posted: Jul 14, 2005 12:50 PM
|
|
> > interface Shape {
> contract {
> draw();
> }
> }
>
> class Line {
> draw() {
> /* draw line */
> }
> }
>
> class Circle {
> public {
> draw() {
> /* draw circle */
> }
> }
> }
>
> f(Shape s) {
> s.draw();
> }
>
> > That's all there is to it :-)
I see. Yes, it looks like an interesting application of signature-based polymorphism, that not only works at compile-time (like templates in C++) but also at run-time (similar to interfaces in other languages, but not requiring inheritance to work).
I now understand how there may be an advantage in having concepts as types, somehow, in that you get run-time polymorphism, that way. With the C++ proposals, the type is deduced at compile-time, so any run-time polymorphism needs the usual inheritance-based approach (at least when it comes to what there's language support for).
There's a similar synergy between the concept proposals and the DbC proposal in C++, where concepts check conformance at compile-time (the part of the concept that may be compile-time checked), and contracts check the run-time requirements.
However, the DbC proposal checks the conformance of (compile-time resolved) types, not "run-time concepts".
> Yes, the Heron concept provides that when it is required. > It intelligently chooses between dynamic dispatching and > type replacement.
Nice.
> Heron concepts > can be used as you would expect a C++0x concept to be > used: > > > concept SortableArray[T : type] {
> inherits {
> Array[T];
> }
> contract {
> Swap(int n1, int n2) {
> pre {
> n1 >= 0);
> }
> Compare(int n1, int n2) : int;
> }
> public {
> Sort() { ... }
> }
> }
>
> concept Comparable {
> public {
> Compare(self x) : int;
> }
> }
>
> class MyArray[T : Comparable] {
> public {
> _init(int n) { ... }
> GetAt(int n) : T { ... }
> SetAt(T n) : T { ... }
> Swap(int n1, int n2) { ... }
> Compare(int n1, int n2) : int { ... }
> }
> }
How does Heron's concepts check conformance? In the C++ proposals, there are two approaches:
1) Name-based conformance: You have to explicitly specify that a type models a concept
2) Signature-based conformance: If a type matches the signatures of the concept, it's taken as a match
Based on your Shape/Line/Circle example, it seems 2) is used. There's then a potential issue of "accidental conformance". As "the Guru" in the CUJ "Conversations"-series might have said it: :) Consider this parable (quoting from your example):
interface Shape { contract { draw(); } }
class DeckOfCards { public { draw() { /* draw a card */ } } } drawShape(Shape s) { s.draw(); }
DeckOfCards d;
drawShape(d); // Oops, not that kind of draw.
This example may be a bit contrieved, but at the last C++ standards meeting (at Lillehammer), the "Indiana"-gang (Jeremy Siek and Doug Gregor) - whose concept proposal uses named conformance - showed an example of how signature-based conformance (Bjarne Stroustrup and Gabriel Dos Reis' concept proposal) may not work with some types, because there may be types that are "structually equal", but having different semantics. Their example was an istream_iterator, which is an input-iterator (so the range it delimits can only be read once), but which you can't distinguish, just based on the signature, from a forward iterator (where you may pass over the range multiple times).
> By the way this is a great discussion, and is really > helping me hone and clarify my ideas. Thanks!
Likewise. :)
Regards,
Terje
|
|