diff --git a/_01.Language-basics.sz b/_01.Language-basics.sz index 1844606..14b9eff 100644 --- a/_01.Language-basics.sz +++ b/_01.Language-basics.sz @@ -2101,6 +2101,28 @@ A trait has exactly one implementor type. When a method needs another type that This is how the prelude's own @code{Iterable}, @code{Collection} and @code{Refable} work, and why @code{length} and @code{fold} work on so many types. +@subsubsection{Implementations for particular type arguments} + +An implementation may be written for a generic type at particular type arguments, and one type may have several, one for each: + +@codeblock[#:lang "bjolang"]|{ +(impl (Describe (List int)) + (defun (describe xs) "some numbers")) + +(impl (Describe (List string)) + (defun (describe xs) "some words")) + +(describe (list 1 2)) ;; "some numbers" +(describe (list "a" "b")) ;; "some words" +}| + +The compiler picks the one whose arguments match. Two rules keep that choice unambiguous: + +@itemlist[ + @item{Two implementations may not overlap. With @code{(List int)} already there, @code{(impl (Describe (List %a)) ...)} is refused, since a @code{(List int)} would then have two.} + @item{The type has to be known where the call is. @code{(describe (list))} is an error, because an empty list could be either, and so is a call at @code{(List %a)} in a generic function: neither implementation is written for every element type. Give such a value an annotation, or write one implementation for @code{(List %a)} with a @code{where}, as in the next section.} +] + @subsubsection{Conditional and blanket implementations} An implementation for a generic type can require something of its type variables, with a @code{where} after the head. A list can be described if its elements can: @@ -2114,7 +2136,7 @@ An implementation for a generic type can require something of its type variables (describe (list Clubs Hearts)) ;; "clubs, hearts" }| -A blanket implementation is one for a bare type variable. It applies to every type that has no implementation of its own, and a more specific implementation always wins over it. Only the module that declares a trait may write its blanket: +A blanket implementation is one for a bare type variable. It applies to every type that has no implementation of its own, and a more specific implementation always wins over it. A type whose head has implementations only for other arguments, such as a @code{(List bool)} beside the @code{(List int)} above, is an error rather than the blanket. Only the module that declares a trait may write its blanket: @codeblock[#:lang "bjolang"]|{ (def/trait (Weight %a)