summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-03-14 19:49:32 +0100
committerAraq <rumpf_a@web.de>2015-03-14 19:49:32 +0100
commit15920675668a2296d34b7ca14ab3185a0ed6ace8 (patch)
tree548e622d7dba78f389898d57ca0af122fec7e2d1
parent2f4472963fca55de312c962cdc648f37bd6838e1 (diff)
downloadNim-15920675668a2296d34b7ca14ab3185a0ed6ace8.tar.gz
improved the documentation; overloading resolution finally documented
-rw-r--r--doc/manual/type_rel.txt169
-rw-r--r--doc/manual/types.txt20
2 files changed, 179 insertions, 10 deletions
diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt
index 74539f907..d1593a02e 100644
--- a/doc/manual/type_rel.txt
+++ b/doc/manual/type_rel.txt
@@ -18,7 +18,7 @@ algorithm (in pseudo-code) determines type equality:
     incl(s, (a,b))
     if a.kind == b.kind:
       case a.kind
-      of int, intXX, float, floatXX, char, string, cstring, pointer, 
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
           bool, nil, void:
         # leaf type: kinds identical; nothing more to check
         result = true
@@ -61,7 +61,7 @@ with an auxiliary set ``s`` is omitted:
   proc typeEqualsOrDistinct(a, b: PType): bool =
     if a.kind == b.kind:
       case a.kind
-      of int, intXX, float, floatXX, char, string, cstring, pointer, 
+      of int, intXX, float, floatXX, char, string, cstring, pointer,
           bool, nil, void:
         # leaf type: kinds identical; nothing more to check
         result = true
@@ -90,7 +90,7 @@ with an auxiliary set ``s`` is omitted:
       result = typeEqualsOrDistinct(a.baseType, b)
     elif b.kind == distinct:
       result = typeEqualsOrDistinct(a, b.baseType)
-      
+
 
 Subtype relation
 ----------------
@@ -145,7 +145,7 @@ algorithm returns true:
 
 A type ``a`` is **explicitly** convertible to type ``b`` iff the following
 algorithm returns true:
- 
+
 .. code-block:: nim
   proc isIntegralType(t: PType): bool =
     result = isOrdinal(t) or t.kind in {float, float32, float64}
@@ -156,8 +156,8 @@ algorithm returns true:
     if typeEqualsOrDistinct(a, b): return true
     if isIntegralType(a) and isIntegralType(b): return true
     if isSubtype(a, b) or isSubtype(b, a): return true
-    
-The convertible relation can be relaxed by a user-defined type 
+
+The convertible relation can be relaxed by a user-defined type
 `converter`:idx:.
 
 .. code-block:: nim
@@ -174,7 +174,7 @@ The convertible relation can be relaxed by a user-defined type
   x = chr.toInt
   echo x # => 97
 
-The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and 
+The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and
 ``typeEqualsOrDistinct(T, type(a))`` holds.
 
 
@@ -186,6 +186,157 @@ An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an
 
 
 Overloading resolution
-----------------------
+======================
+
+In a call ``p(args)`` the routine ``p`` that matches best is selected. If
+multiple routines match equally well, the ambiguity is reported at compiletime.
+
+Every arg in args needs to match. There are multiple different category how an
+argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
+of the argument.
+
+1. Exact match: ``a`` and ``f`` are of the same type.
+2. Literal match: ``a`` is an integer literal of value ``v``
+   and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s
+   range. Or:  ``a`` is a floating point literal of value ``v``
+   and ``f`` is a floating point type and ``v`` is in ``f``'s
+   range.
+3. Generic match: ``f`` is a generic type and ``a`` matches, for
+   instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter
+   type (like in ``[T]`` or ``[T: int|char]``.
+4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T``
+   matches ``f`` exactly. Or: ``a`` is a subtype of ``f``.
+5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a``
+   is some integer or floating point type.
+6. Conversion match: ``a`` is convertible to ``f``, possibly via a user
+   defined ``converter``.
+
+These matching categories have a priority: An exact match is better than a
+literal match and that is better than a generic match etc. In the following
+``count(p, m)`` counts the number of matches of the matching category ``m``
+for the routine ``p``.
+
+A routine ``p`` matches better than a routine ``q`` if the following
+algorithm returns true::
+
+  for each matching category m in ["exact match", "literal match",
+                                  "generic match", "subtype match",
+                                  "integral match", "conversion match"]:
+    if count(p, m) > count(q, m): return true
+    elif count(p, m) == count(q, m):
+      discard "continue with next category m"
+    else:
+      return false
+  return "ambiguous"
+
+
+Some examples:
+
+.. code-block:: nim
+  proc takesInt(x: int) = echo "int"
+  proc takesInt[T](x: T) = echo "T"
+  proc takesInt(x: int16) = echo "int16"
+
+  takesInt(4) # "int"
+  var x: int32
+  takesInt(x) # "T"
+  var y: int16
+  takesInt(y) # "int16"
+  var z: range[0..4] = 0
+  takesInt(z) # "T"
+
+
+If this algorithm returns "ambiguous" further disambiguation is performed:
+If the argument ``a`` matches both the parameter type ``f`` of ``p``
+and ``g`` of ``q`` via a subtyping relation, the inheritance depth is taken
+into account:
+
+.. code-block:: nim
+  type
+    A = object of RootObj
+    B = object of A
+    C = object of B
+
+  proc p(obj: A) =
+    echo "A"
+
+  proc p(obj: B) =
+    echo "B"
+
+  var c = C()
+  # not ambiguous, calls 'B', not 'A' since B is a subtype of A
+  # but not vice versa:
+  p(c)
+
+  proc pp(obj: A, obj2: B) = echo "A B"
+  proc pp(obj: B, obj2: A) = echo "B A"
+
+  # but this is ambiguous:
+  pp(c, c)
+
+
+Likewise for generic matches the most specialized generic type (that still
+matches) is preferred:
+
+.. code-block:: nim
+  proc gen[T](x: ref ref T) = echo "ref ref T"
+  proc gen[T](x: ref T) = echo "ref T"
+  proc gen[T](x: T) = echo "T"
+
+  var ri: ref int
+  gen(ri) # "ref T"
+
+
+Overloading based on 'var T'
+----------------------------
+
+If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
+type checking, the argument is checked to be an `l-value`:idx:. ``var T``
+matches better than just ``T`` then.
+
+
+Automatic dereferencing
+-----------------------
+
+If the `experimental mode <experimental pragma>`_ is active and no other match
+is found, the first argument ``a`` is dereferenced automatically if it's a
+pointer type and overloading resolution is tried with ``a[]`` instead.
+
+
+Lazy type resolution for expr
+-----------------------------
+
+**Note**: An `unresolved`:idx: expression is an expression for which no symbol
+lookups and no type checking have been performed.
+
+Since templates and macros that are not declared as ``immediate`` participate
+in overloading resolution it's essential to have a way to pass unresolved
+expressions to a template or macro. This is what the meta-type ``expr``
+accomplishes:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+
+  rem unresolvedExpression(undeclaredIdentifier)
+
+A parameter of type ``expr`` always matches any argument (as long as there is
+any argument passed to it).
+
+But one has to watch out because other overloads might trigger the
+argument's resolution:
+
+.. code-block:: nim
+  template rem(x: expr) = discard
+  proc rem[T](x: T) = discard
+
+  # undeclared identifier: 'unresolvedExpression'
+  rem unresolvedExpression(undeclaredIdentifier)
+
+``expr`` is the only metatype that is lazy in this sense, the other
+metatypes ``stmt`` and ``typedesc`` are not lazy.
+
+
+Varargs matching
+----------------
 
-To be written.
+See `Varargs`_.
diff --git a/doc/manual/types.txt b/doc/manual/types.txt
index a20701121..c78984db8 100644
--- a/doc/manual/types.txt
+++ b/doc/manual/types.txt
@@ -497,6 +497,24 @@ type conversions in this context:
 In this example ``$`` is applied to any argument that is passed to the
 parameter ``a``. (Note that ``$`` applied to strings is a nop.)
 
+Note that an explicit array constructor passed to a ``varargs`` parameter is
+not wrapped in another implicit array construction:
+
+.. code-block:: nim
+  proc takeV[T](a: varargs[T]) = discard
+
+  takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+
+
+``varargs[expr]`` is treated specially: It matches a variable list of arguments
+of arbitrary type but *always* constructs an implicit array. This is required
+so that the builtin ``echo`` proc does what is expected:
+
+.. code-block:: nim
+  proc echo*(x: varargs[expr, `$`]) {...}
+
+  echo(@[1, 2, 3])
+  # prints "@[1, 2, 3]" and not "123"
 
 
 Tuples and object types
@@ -695,7 +713,7 @@ via ``{.experimental.}``:
   new(n)
   echo n.depth
   # no need to write n[].depth either
-  
+
 
 
 In order to simplify structural type checking, recursive tuples are not valid: