Posted: Mar 23, 2012 3:28 am
by mizvekov
VazScep wrote:Hmm...could you restrict the inference to the use of concepts though?

By the way, I have read your example again, and now I think I understand what you want to do.
I will try to rewrite it to something which would compile, and tell me if that's what you meant:
Code: Select all
template<typename T> requires FooConcept<T>
T foo() {

template<typename T>
T bar() {
   return foo<T>();

And even though it might seem simple here, I think there is no way to do this kind of stuff for all templates.
I think you are saying that from that example, it would seem obvious that bar would also require FooConcept<T>
But suppose foo also has a specialization for another type, like here:
Code: Select all
template<typename T> requires FooConcept<T>
T foo() {

char foo<char>() {

template<typename T>
T bar1() {
   return foo<T>();

template<typename T> requires FooConcept<T>
T bar2() {
   return foo<T>();

And now bar1 accepts T as char, but bar2 does not.

VazScep wrote:I've read (since my last post) that the way you would manually typecheck something like "bar" is to construct an archetype that minimally implements the concept. Hopefully, that could be done automatically, by automatically constructing the archetype. But I'm tempted to think this should just be an option for compiler writers.

But automatically build the archetypes from what information?
The body of the templates which uses the type? I don't think that could be workable as I said above. Besides the problems I mentioned for convoluted templates, I think there could be a lot of ambiguities there too. Consider the below code:
Code: Select all
template<typename T> void foo(T a) { bar(a, 2.0); }

Now, which of the below concepts would the compiler choose so that T would be required to satisfy:
Code: Select all
concept C1<typename T> { void bar(T, double); }
concept C2<typename T> { void bar(T, float); }
concept C3<typename T> { void bar(T, int); }
concept C4<typename T> { int bar(T, double); }
concept C5<typename T> {
   void bar(T, double);
   void bar(T, float);
   void bar(T, int);
   int bar(T, double);

And I could go on all day.

VazScep wrote:There's ConceptGCC! It sounds like it's seriously prototype at the moment, though.

Yay, thought that the patch to implement it was just discontinued, but they decided to just fork GCC instead!
So I suppose we will be able to try it out a lot sooner :)

VazScep wrote:As I understand, if you declare a concept as auto, then no inference actually happens. It just means you don't need a concept map, and so concept-satisfaction will happen at template-expansion time. Is that right?

Yes that's right, I think so.

VazScep wrote:I don't expect C++ to infer arbitrary concepts without explicit concept annotations, though, since presumably, there could be multiple concepts that a type could satisfy. You can have concepts that overlap right?

Yes ofcourse. You can also have a concept which enforces a restriction on any number of types. For example:
Code: Select all
concept C1<typename T, typename U> {
  void bar(T, U);

template<typename T, typename U> requires C1<T, U>
void f(T t, U u) {
  bar(t, u);

VazScep wrote:I'm not yet convinced :P Many of the GHC extensions give you a Turing complete type-theory too.

VazScep wrote:
The template expansion doesn't necessarily give you code bloat though. Compilers will normally implement a final step of merging code of template instances which are similar, but it's just an heuristic anyway.
Ah, this is interesting. Can you point me to some documentation about this?

Well, that's hard to do, as this is something not mandated by the standard. This is usually one of the many tricks that compilers do, and I came to see them through experimentation and by talking to others and reading articles. I simply am not finding such documentation.
One thing that you can certainly expect of any compiler is that it will at least remove duplicated instantiations which happened in different compilation units. When you try to link them together to form an executable or whatever, the linker will discard duplicates and keep only one copy.
Another thing that some compilers implement is that if a function has exactly the same code in two different instantiations of the same template (as in different template parameters), then the duplicated code will be discarded, and only one will be used instead.

VazScep wrote:It doesn't have the Ocaml module system unfortunately. But it has lots of other cool stuff, such as type-inferred dimensional types, which are awesome. I've had the compiler reject my F# code, and point me to a logic error where I was trying to add a distance to a velocity because of a careless placement of brackets. Without the type-checking, I'm not sure how long I would have spent tracking the bug.

Cool :)
How does that work? do you have an example?

VazScep wrote:Again, this is interesting. Do you know what the tradeoffs are?

Well, by declaring an instance as extern, the compiler does not have to instantiate it again at every compilation unit, only to then have the linker discard the multiple copies. This results in huge compilation time savings for some cases.
One possible downside is that the compiler will have to rely on link time optimization in order to do such things as inlining.
VazScep wrote:How does use of "extern" mesh with dynamically linked libraries? If there are issues, are they even that big a deal?

Dll are not directly supported by neither the C nor the C++ standard, and how to implement them is very platform dependent.

It does not change anything anyway since there is no standard abi for c++ code, and so when you write dll's your only real option is to export functions as C (with extern "C"). You could do otherwise, but then if you tried to create an executable in visual studio which uses a dll created in g++, it would just not work, most likely it would segfault.

If you need this kind of functionality in c++ code, then you would probably need something like microsoft COM or CORBA.
I have never used those two, but I don't think it makes sense to say that you would need to export a generic class or generic function through them. I suppose that you would instead have a generic 'thing' and then use whatever mechanisms these systems provide to export an instance of that thing.
In that case, I also don't see how the 'extern' changes anything significantly.

VazScep wrote:Hey, it's a significant advance. Axiomatic constraints are normally just given in documentation, which is not machine-readable. That's the most significant barrier to formal verification.

I see :)
Well yes that's indeed very cool, but I just meant that I thought we wouldn't be seeing any compilers implementing it so soon.