I consider this possibility a very useful even without additional checks (those 
in the concept body), like of existence of procedures defined for the type with 
stated signatures and the like, exactly because the programmer explicitly 
declares the purpose of his type and what can be done with, what functionality 
is really supported by the type. I think this explicit promise/contract is the 
main point for interfaces in Delphi, Java, PHP, C#, and signature checking is 
additional to that.

I'll try to make it more visual:
    
    
    type Browser = concept type b
      proc goTo(self: b, url: string)
      proc back(self: b)
      proc forward(self: b)
    proc makeSomeStuffWithABrowser(br: Browser) = 
br.goTo("http://www.nim-lang.org/";)
    
    # creating a concrete type satisfying the concept
    type MySimpleBrowser = distinct int # whatever it would be
    proc goTo(self: MySimpleBrowser, url: string) = echo "going to " & url & " 
with MySimpleBrowser"
    proc back(self: MySimpleBrowser) = discard
    proc forward(self: MySimpleBrowser) = discard
    
    # using it
    var sb: MySimpleBrowser
    makeSomeStuffWithABrowser(sb) # it works, well; it should
    
    # here we don't want to define another Browser, just an unrelated type; 
maybe in another module
    type FileManager = distinct int
    proc goTo(self: FileManager, path: string) = echo "going to " & path & " 
with X"
    proc back(self: FileManager) = discard
    proc forward(self: FileManager) = discard
    
    var fm: FileManager
    # and here by accident...
    makeSomeStuffWithABrowser(fm) # works too :(
    

Lando's suggestion is perfect in my view, if not to restrict it to object type 
- it can fit equally well any types, as concepts do. It can be seen like a type 
class (like e.g. `SomeReal* = float|float32|float64`), but extendable and with 
inverse binding: created empty and populated with concrete types at their 
definition site. Like:
    
    
    type X = explicit concept c
      # ...
    # X here matches no concrete types, regardless of checks in the concept body
    type Y = distinct int satisfies X # conditions in X concept body are 
checked,
                                      # compile-time error, if not satisfied;
                                      # Y is added to the list of 
implementations for X
    type Z = distinct int satisfies X
    proc p(x: X) = discard
    # here the same as p(x: Y|Z)
    

Regarding wording, `explicit concept` and `satisfies` seem to be not worse than 
usual `interface` and `implements`, especially taking into account 
distinctions; just for people coming from those languages those terms may be 
more familiar; maybe `explicit concept` will be easier to understand to others.

Regarding implementation, macro vs. built-in: I wanted to implement such a 
thing some (long) time ago via macros and concepts and was faced then with some 
VM limitations; maybe they were eliminated from then. The intended syntax was 
(for simplicity):
    
    
    type X = ...
    implements X, I
    

Reply via email to