Re: syntax suggestion for concepts
On Mar 7, 3:59 pm, "Andrei Polushin" <polus...@gmail.com> wrote:
Douglas Gregor wrote:
Yes. This is typically called "dictionary passing", and is the
implementation technique used by both Haskell and G.
In a sense, this is the same way that C++ concepts are implemented,
but the dictionary is passed at compile time, not run time.
Interestingly, would we call it "generic programming" or whatever, it
is still implemented with an OO programming, as OO is the most generic
programming style :)
By this logic, spaghetti code is the most generic programming style :)
What's OO turn implemented with? Procedural Programming.
What's Procedural Programming implemented with? Unstructured
Programming.
What's Unstructured Programming? Spaghetti!
On a more serious note, one can implement run-time dispatched GP code
using OO techniques, but the objects themselves essentially become
meaningless... th7re used only for the dynamic dispatching present in
their vtables, essentially just a bucket of function pointers. It's
not a very enlightened use of OO, but if OO is all you have to build
on...
One of the typical Generic Programming complaints about OO is that it
ties together the questions of "What can this type do?" and "How is
this type implemented?" into the same language mechanism: inheritance.
Yes. And we have a notion of "interface" that doesn't deal with
implementation, and a "mixin class" that is implementation-only.
Yes, mixins were mentioned in the blurb I linked to originally
http://www.generic-programming.org/faq/?category=paradigms#object-oriented-programming
because they do address part of the problem.
Mixins still tie the questions "What can this type do?" and "How is
this type implemented?" together. Yes, they can be mixed in after the
type is created (and that's good!), but they still answer both
questions with the same answer, inheritance. Here's an example where
this begins to get in the way:
interface Shape {
void draw();
}
interface Gunslinger {
void draw();
}
Now, I want to have a class YosemiteSam (a gun-toting cartoontoon
character):
class YosemiteSam { ... }
YosemiteSam is a shape, so we want to mix-in a subclass that makes
YosemiteSam implement Shape:
mixin class YosemiteSamAsShape implements Shape {
void draw() { /* see http://en.wikipedia.org/wiki/Yosemite_Sam
*/ }
}
// mix that into YosemiteSam, of course
Then we want YosemiteSam to be a Gunslinger, so he can participate in
the WildWildWest:
mixin class YosemiteSamAsGunslinger implements Gunslinger {
void draw() { /* pull out both of his pistols at once */ }
}
// mix that into YosemiteSam, of course
Now we have a YosemiteSam that inherits the mixins YosemiteSameAsShape
and YosemiteSamAsGunslinger, and therefore implements both the Shape
and Gunslinger interfaces. Do those interfaces each get the right
"draw" methods? If so, how are the mixins arranged to ensure that this
happens? If not, we've run into a problem with expressing everything
in terms of inheritance, because different mixins for completely
different purposes have now collided in the same class.
With Generic Programming, there is no such collision because the
various different ways of viewing YosemiteSam---as a Shape or as a
Gunslinger---are kept completely separate, in different concept maps:
concept_mappe<YosemiteSam> { void draw() { ... } }
concept_map Gunslinger<YosemiteSam> { void draw() { ... } }
Those draw() functions (not "methods") live in the concept map, not in
YosemiteSam. So the implementation of YosemiteSam is completely opaque
to all but the author. Generic/polymorphic functions only see the view
of YosemiteSam that they've asked for, e.g., as a Shape or as a
Gunslinger.
The first question is the more important question for someone writing
a polymorphic algorithm, because we don't care what the type is...
In OO programming, we also able to forget about the exact type, we can
just work with its "interface".
Right, but now you're working with two objects known only by their
common interface, say, Shape, and you have no idea whether those two
objects have the same actual type or are completely different, because
you've thrown away valuable type information. This is, again, the
binary method problem. Well-known, well-studied, and the typical
answers are either multi-methods or a "self" type.
I would have to recall the same solution mentioned in D&E 13.8
(Stroustrup says the idea was suggested by Doug Lea in 1991):
bool intersect(virtual const Shape& , virtual const Shape& );
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]