Yigal Chripun wrote: > Lutger wrote: >> Not sure what that would do, but C++ concepts are not exactly compile >> time interfaces. This is very important: in C++0X, a type T which >> satisfies the concept Comparable<T> does not implement the concept >> explicitly, whereas languages with explicit constraints on generics do >> require T to be inherited from IComparable. The consequence is a bit of >> bloat and more rigid demands on what is supposed to relax the inflexible >> regime of the static type system. This bloat and rigidity is also a >> cognitive burden in it's own right, for example when it requires >> workarounds when the system is not expressive enough. > > regarding the consequences - i agree that this is a bit more rigid. I > don't see the bloat though. can you provide an example? can you also > explain what kinds of workarounds are you talking about that would be > required?
Ok, I sort of assumed you talked about explicit instantiation like in C#. For any type that implements a clone operation for example, you have to derive it from ICloneable if you are to use it as a generic parameter. In addition, in your template, you have to explicitly bring all operations under in an interface. (This is the bloat part). Now say I have a type from another library that supports cloning, has the same interface as ICloneable, but doesn't derive from it. You are forced to create a wrapper for it that derives from ICloneable. (the workaround). Also, there is the complication of what to do with arithmetic types. >> >> Concepts provide two benefits in this context: documentation and extra >> type checking for templates. But they do retain structural typing. In D, >> we already have this covered with template constraints.* If you look at >> std.range, this is exactly what you see: all the interfaces (and even >> semantics) are nicely named and documented explicitly. So would we have >> had compile time interfaces, they would add next to nothing about the >> documentation or understanding of ranges. >> > > there are several problems with the template constraints currently used. > 1. the constraints are specified on the client code which means you need > to either duplicate those constraints everywhere or call some template > like isForwardRange manually to check that you got the correct type. Yes that is the way to go I believe. Phobos already defines a lot of these concepts so that makes it easier. > 2. The syntax for this is completely alien and unreadable, at least for > me. I agree, but this is a syntax detail. It has no bearing on the type system. > documentations and type-checking are indeed the two main benefits I'd > like to get. > the current way it is done with is() expression is unreadable. this > needs to be specified IMO with the same (or almost the same) syntax as > interfaces. I don't get why D needs two completely different syntaxes > for the same thing (specifying an interface). this will give us a more > readable documentation aspect. > the type-checking aspect of this is that the checks will be done on the > template definition instead of the instantiation in the client code > which will also prevent cases when bugs in a library template only > manifest when the client programmer compiles *his* code. this happened > to tango in the past. I agree. This is point where concepts in C++ may prove more powerful. >>> templates are hard for users to understand and one of the main reasons >>> for this is that templates are essentially a completely different >>> language with different syntax and semantics which to me looks like >>> mis-design. >> >> I don't think it is hard to understand because of structural typing. >> Generics are inherently somewhat difficult in a static typing language, >> because of it's abstract nature. You don't have this problem in dynamic >> languages. (or you can't escape it, depending on your POV) >> >> I don't agree that templates are a completely different language though. >> When used purely for parametric polymorphism, it does integrate nicely in >> the normal type system. When you do use it for meta-programming, which is >> relatively rare, then the above also applies: this is an inherently >> difficult way of programming. Just look at something like lisp where you >> can metaprogram in the same language. Does that make it easy to >> understand? Or CTFE and string mixins in D, same language, but it's also >> difficult. Adding more constraints can never solve the fact that humans >> don't easily grok programs which generate programs. >> > I was talking mostly about meta-programming and not parametric > polymorphism. > I agree that it is harder to grok programs that generate programs. this > is why it is so important IMO to make this as readable as possible. > to answer your question, lisp does make this _easier_ to understand > compared to templates. D CTFE functions are much more readable than D > templates. > while I agree that this is never trivial, it should not be made near > impossible like it is in C++. an experienced user should be able to read > the source of libs like Boost and STL and understand without much > trouble what it does without being a C++ guru. > >> * I don't think the extra type checking is done, but perhaps it could be. >> > > the distinction you make between generics with explicit constraints that > require explicit inheritance and concepts is more of an implementation > detail IMO. > the first uses run-time inheritance for this type checking. > what I'd prefer is the second implementation where the type-check is > done at compile-time by means of structural typing but unlike C++ where > it's optional I want it to be required so that the type-checking is > performed on the definition and not on the instantiations. > does that make sense? I don't understand how you can have structural typing and at the same time require explicit constraints. Maybe I'm missing something here? This was my entire point: losing structural typing because of explicit generic constraints is a bad thing.
