Yes, it's possible to use predicates such as `not compiles()` within the 
concept body, but I think what you are really after here is support for the 
notion of "more-specific" in the overload resolution process.

Besides the concept refinement explained in the manual, types such as 
`Stack[Hashable]` can be considered more specific than types such as `Stack[T]` 
(where `T` is a completely unrestricted generic param - the so called `any` 
type). The most natural way to provide optimized algorithms is to provide a 
"more-specific" overload like this:
    
    
    type
      Hashable = concept v
        hash(v) is int
      
      Stack[T] = object # or concept
        ...
    
    proc myAlgorithm(s: Stack) = ...
    proc myAlgorithm(s: Stack[Hashable]) = ... optimized version ...
    

Implementing this "more-specific" rule is the most risky change I need to 
introduce in the compiler, because it has the potential to break a lot of 
existing code. Both Araq and me have longed for it in the past, but the current 
overload scoring system is complicated and it would be hard to tweak it in a 
fully backwards-compatible way (so, no promises here yet).

* * *

Before addressing the questions asking what happens when a type matches 
multiple variations of a concept, I must say that I find this situation a bit 
too hypothetical. Consider the human factors involved when concepts are created 
and used. Every concept is born like this:

  1. Developer A creates a library of algorithms in a certain problem domain
  2. Developer A says "Hey, you can use these algorithms with your own types. 
All you have to do is conform to this simple set of requirements"
  3. Developer B (who can be the same person) says "What a useful library, let 
me adapt my types to it by implementing the required interface"



In your example, developer B had made some additional specific steps designed 
to confuse and break the concept matching process. Obviously, developer B 
doesn't have a good reason to do this, so we must consider only the case where 
this problem was caused by accident (i.e. the concrete types of developer B 
accidentally use the same proc names in a different and incompatible way). For 
the later to be true, a rather long list of requirements must be met - the 
problematic procs must have a matching number or arguments, the inferred types 
must not be used in multiple places in the concept body, because this is likely 
to quickly resolve the ambiguous type and finally the ambiguous type must be 
used in a way that breaks the actual algorithmic procs in the library of 
developer A. I'd say all of this is rather unlikely.

* * *

But to answer your questions, the inference process directly follows from the 
body of the concept. If a type conforms to both `Map[int, string]` and 
`Map[string, int]`, then the following overloads must exist:
    
    
    c[int] = string
    c[string] = int
    

>From this, we can see that both `K` and `V` will be indeed inferred as 
>`int|string` on the first line of the `MapComparable` concept. On the second 
>line, the compiler will try to verify whether an overload exists for 
>`string|int < string|int`. Such checks involve the full cartesian product of 
>the involved types. There are various possible outcomes:

  * Only one variant exists (e.g. `int < string`) - `K` and `V` will be 
"collapsed" to `int` and `string` respectively
  * All variants exists (`int < string`, `string < int`, `string < string` and 
`int < int`) - the types will remain in their superposition
  * None of the overloads is found - the concept doesn't match



If there are more lines in the concept body, the process will continue.

Reply via email to