diff options
author | Araq <rumpf_a@web.de> | 2015-03-14 19:49:32 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2015-03-14 19:49:32 +0100 |
commit | 15920675668a2296d34b7ca14ab3185a0ed6ace8 (patch) | |
tree | 548e622d7dba78f389898d57ca0af122fec7e2d1 | |
parent | 2f4472963fca55de312c962cdc648f37bd6838e1 (diff) | |
download | Nim-15920675668a2296d34b7ca14ab3185a0ed6ace8.tar.gz |
improved the documentation; overloading resolution finally documented
-rw-r--r-- | doc/manual/type_rel.txt | 169 | ||||
-rw-r--r-- | doc/manual/types.txt | 20 |
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: |