summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2018-04-23 22:30:23 +0300
committerZahary Karadjov <zahary@gmail.com>2018-06-16 16:46:32 +0300
commitea36e0ebbe0033b304a1261de802e2ed9308abf4 (patch)
treeb0c182226dbd97e52b1ef7ee09d119e3da052f77
parenta49b06a52a3c24258e9eb04593a2f83ae057755f (diff)
downloadNim-ea36e0ebbe0033b304a1261de802e2ed9308abf4.tar.gz
document the new `type[T]` and `static[T]` features
-rw-r--r--changelog.md7
-rw-r--r--doc/docgen.rst6
-rw-r--r--doc/manual.rst156
-rw-r--r--doc/tut2.rst6
4 files changed, 104 insertions, 71 deletions
diff --git a/changelog.md b/changelog.md
index 4067cb693..2e75d8ad9 100644
--- a/changelog.md
+++ b/changelog.md
@@ -116,6 +116,13 @@
 - In order to make ``for`` loops and iterators more flexible to use Nim now
   supports so called "for-loop macros". See
   the `manual <manual.html#macros-for-loop-macros>`_ for more details.
+- the `typedesc` special type has been renamed to just `type`.
+- `static` and `type` are now also modifiers similar to `ref` and `ptr`.
+  They denote the special types `static[T]` and `type[T]`.
+- Forcing compile-time evaluation with `static` now supports specifying
+  the desired target type (as a concrete type or as a type class)
+- The `type` operator now supports checking that the supplied expression
+  matches an expected type constraint.
 
 ### Language changes
 
diff --git a/doc/docgen.rst b/doc/docgen.rst
index e6693e153..d196b3a18 100644
--- a/doc/docgen.rst
+++ b/doc/docgen.rst
@@ -303,9 +303,9 @@ symbols in the `system module <system.html>`_.
   `#len,seq[T] <system.html#len,seq[T]>`_
 * ``iterator pairs[T](a: seq[T]): tuple[key: int, val: T] {.inline.}`` **=>**
   `#pairs.i,seq[T] <system.html#pairs.i,seq[T]>`_
-* ``template newException[](exceptn: typedesc; message: string): expr`` **=>**
-  `#newException.t,typedesc,string
-  <system.html#newException.t,typedesc,string>`_
+* ``template newException[](exceptn: type; message: string): expr`` **=>**
+  `#newException.t,type,string
+  <system.html#newException.t,type,string>`_
 
 
 Index (idx) file format
diff --git a/doc/manual.rst b/doc/manual.rst
index 8e548afdc..88dae89b0 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -1732,7 +1732,7 @@ But it seems all this boilerplate code needs to be repeated for the ``Euro``
 currency. This can be solved with templates_.
 
 .. code-block:: nim
-  template additive(typ: typedesc) =
+  template additive(typ: type) =
     proc `+` *(x, y: typ): typ {.borrow.}
     proc `-` *(x, y: typ): typ {.borrow.}
 
@@ -1740,13 +1740,13 @@ currency. This can be solved with templates_.
     proc `+` *(x: typ): typ {.borrow.}
     proc `-` *(x: typ): typ {.borrow.}
 
-  template multiplicative(typ, base: typedesc) =
+  template multiplicative(typ, base: type) =
     proc `*` *(x: typ, y: base): typ {.borrow.}
     proc `*` *(x: base, y: typ): typ {.borrow.}
     proc `div` *(x: typ, y: base): typ {.borrow.}
     proc `mod` *(x: typ, y: base): typ {.borrow.}
 
-  template comparable(typ: typedesc) =
+  template comparable(typ: type) =
     proc `<` * (x, y: typ): bool {.borrow.}
     proc `<=` * (x, y: typ): bool {.borrow.}
     proc `==` * (x, y: typ): bool {.borrow.}
@@ -2396,7 +2396,7 @@ argument's resolution:
   rem unresolvedExpression(undeclaredIdentifier)
 
 ``untyped`` and ``varargs[untyped]`` are the only metatype that are lazy in this sense, the other
-metatypes ``typed`` and ``typedesc`` are not lazy.
+metatypes ``typed`` and ``type`` are not lazy.
 
 
 Varargs matching
@@ -4274,29 +4274,6 @@ therefore very useful for type specialization within generic code:
         deletedKeys: seq[bool]
 
 
-Type operator
--------------
-
-The ``type`` (in many other languages called `typeof`:idx:) operator can
-be used to get the type of an expression:
-
-.. code-block:: nim
-  var x = 0
-  var y: type(x) # y has type int
-
-If ``type`` is used to determine the result type of a proc/iterator/converter
-call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the
-interpretation where ``c`` is an iterator is preferred over the
-other interpretations:
-
-.. code-block:: nim
-  import strutils
-
-  # strutils contains both a ``split`` proc and iterator, but since an
-  # an iterator is the preferred interpretation, `y` has the type ``string``:
-  var y: type("a b c".split)
-
-
 Type Classes
 ------------
 
@@ -4450,10 +4427,10 @@ the presence of callable symbols with specific signatures:
     OutputStream = concept var s
       s.write(string)
 
-In order to check for symbols accepting ``typedesc`` params, you must prefix
-the type with an explicit ``type`` modifier. The named instance of the type,
-following the ``concept`` keyword is also considered an explicit ``typedesc``
-value that will be matched only as a type.
+In order to check for symbols accepting ``type`` params, you must prefix
+the type with the explicit ``type`` modifier. The named instance of the
+type, following the ``concept`` keyword is also considered to have the
+explicit modifier and will be matched only as a type.
 
 .. code-block:: nim
   type
@@ -4513,7 +4490,7 @@ The concept types can be parametric just like the regular generic types:
   import typetraits
 
   type
-    AnyMatrix*[R, C: static[int]; T] = concept m, var mvar, type M
+    AnyMatrix*[R, C: static int; T] = concept m, var mvar, type M
       M.ValueType is T
       M.Rows == R
       M.Cols == C
@@ -4523,7 +4500,7 @@ The concept types can be parametric just like the regular generic types:
 
       type TransposedType = stripGenericParams(M)[C, R, T]
 
-    AnySquareMatrix*[N: static[int], T] = AnyMatrix[N, N, T]
+    AnySquareMatrix*[N: static int, T] = AnyMatrix[N, N, T]
 
     AnyTransform3D* = AnyMatrix[4, 4, float]
 
@@ -4542,7 +4519,7 @@ The concept types can be parametric just like the regular generic types:
   ### matrix.nim
 
   type
-    Matrix*[M, N: static[int]; T] = object
+    Matrix*[M, N: static int; T] = object
       data: array[M*N, T]
 
   proc `[]`*(M: Matrix; m, n: int): M.T =
@@ -4554,7 +4531,7 @@ The concept types can be parametric just like the regular generic types:
   # Adapt the Matrix type to the concept's requirements
   template Rows*(M: type Matrix): expr = M.M
   template Cols*(M: type Matrix): expr = M.N
-  template ValueType*(M: type Matrix): typedesc = M.T
+  template ValueType*(M: type Matrix): type = M.T
 
   -------------
   ### usage.nim
@@ -4582,7 +4559,7 @@ operator and also when types dependent on them are being matched:
 
 .. code-block:: nim
   type
-    MatrixReducer[M, N: static[int]; T] = concept x
+    MatrixReducer[M, N: static int; T] = concept x
       x.reduce(SquareMatrix[N, T]) is array[M, int]
 
 The Nim compiler includes a simple linear equation solver, allowing it to
@@ -4771,12 +4748,12 @@ object inheritance syntax involving the ``of`` keyword:
 
     # the varargs param will here be converted to an array of StringRefValues
     # the proc will have only two instantiations for the two character types
-    proc log(format: static[string], varargs[StringRef])
+    proc log(format: static string, varargs[StringRef])
 
     # this proc will allow char and wchar values to be mixed in
     # the same call at the cost of additional instantiations
     # the varargs param will be converted to a tuple
-    proc log(format: static[string], varargs[distinct StringRef])
+    proc log(format: static string, varargs[distinct StringRef])
 
 
 ..
@@ -4940,9 +4917,8 @@ templates:
 | ``notin`` and ``isnot`` have the obvious meanings.
 
 The "types" of templates can be the symbols ``untyped``,
-``typed`` or ``typedesc`` (stands for *type
-description*). These are "meta types", they can only be used in certain
-contexts. Real types can be used too; this implies that ``typed`` expressions
+``typed`` or ``type``. These are "meta types", they can only be used in certain
+contexts. Regular types can be used too; this implies that ``typed`` expressions
 are expected.
 
 
@@ -5109,7 +5085,7 @@ In templates identifiers can be constructed with the backticks notation:
 .. code-block:: nim
     :test: "nim c $1"
 
-  template typedef(name: untyped, typ: typedesc) =
+  template typedef(name: untyped, typ: type) =
     type
       `T name`* {.inject.} = typ
       `P name`* {.inject.} = ref `T name`
@@ -5171,7 +5147,7 @@ template cannot be accessed in the instantiation context:
 .. code-block:: nim
     :test: "nim c $1"
 
-  template newException*(exceptn: typedesc, message: string): untyped =
+  template newException*(exceptn: type, message: string): untyped =
     var
       e: ref exceptn  # e is implicitly gensym'ed here
     new(e)
@@ -5493,7 +5469,7 @@ As their name suggests, static parameters must be known at compile-time:
 
 .. code-block:: nim
 
-  proc precompiledRegex(pattern: static[string]): RegEx =
+  proc precompiledRegex(pattern: static string): RegEx =
     var res {.global.} = re(pattern)
     return res
 
@@ -5513,9 +5489,9 @@ Static params can also appear in the signatures of generic types:
 .. code-block:: nim
 
   type
-    Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T]
+    Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T]
       # Note how `Number` is just a type constraint here, while
-      # `static[int]` requires us to supply a compile-time int value
+      # `static int` requires us to supply a compile-time int value
 
     AffineTransform2D[T] = Matrix[3, 3, T]
     AffineTransform3D[T] = Matrix[4, 4, T]
@@ -5523,53 +5499,75 @@ Static params can also appear in the signatures of generic types:
   var m1: AffineTransform3D[float]  # OK
   var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
 
+Please note that ``static T`` is just a syntactic convenience for the
+underlying generic type ``static[T]``. This means that you can omit the
+type param to obtain the type class of all values, known at compile-time
+and you can restrict the matched values by instantiating ``static`` with
+another type class.
 
-typedesc
---------
+You can force the evaluation of a certain expression at compile-time by
+coercing it to a corresponding ``static`` type:
+
+.. code-block:: nim
+  import math
+
+  echo static(fac(5)), " ", static[bool](16.isPowerOfTwo)
 
-`typedesc` is a special type allowing one to treat types as compile-time values
-(i.e. if types are compile-time values and all values have a type, then
-typedesc must be their type).
+The complier will report any failure to evaluate the expression or a
+possible type mismatch error.
 
-When used as a regular proc param, typedesc acts as a type class. The proc
-will be instantiated for each unique type parameter and one can refer to the
-instantiation type using the param name:
+type[T]
+-------
+
+In many contexts, Nim allows you to treat the names of types as regular
+values. These values exists only during the compilation phase, but since
+all values must have a type, ``type`` is considered their special type.
+
+``type`` acts like a generic type. For instance, the type of the symbol
+``int`` is ``type[int]``. Just like with regular generic types, when the
+generic param is ommited, ``type`` denotes the type class of all types.
+As a syntactic convenience, you can also use ``type`` as a modifier.
+``type int`` is considered the same as ``type[int]``.
+
+Procs featuring ``type`` params will be considered implicitly generic.
+They will be instantiated for each unique combination of supplied types
+and within the body of the proc, the name of each param will refer to
+the bound concrete type:
 
 .. code-block:: nim
 
-  proc new(T: typedesc): ref T =
+  proc new(T: type): ref T =
     echo "allocating ", T.name
     new(result)
 
   var n = Node.new
   var tree = new(BinaryTree[int])
 
-When multiple typedesc params are present, they will bind freely to different
-types. To force a bind-once behavior
-one can use an explicit ``typedesc[T]`` generic param:
+When multiple type params are present, they will bind freely to different
+types. To force a bind-once behavior one can use an explicit generic param:
 
 .. code-block:: nim
-  proc acceptOnlyTypePairs[T, U](A, B: typedesc[T]; C, D: typedesc[U])
+  proc acceptOnlyTypePairs[T, U](A, B: type[T]; C, D: type[U])
 
-Once bound, typedesc params can appear in the rest of the proc signature:
+Once bound, type params can appear in the rest of the proc signature:
 
 .. code-block:: nim
     :test: "nim c $1"
 
-  template declareVariableWithType(T: typedesc, value: T) =
+  template declareVariableWithType(T: type, value: T) =
     var x: T = value
 
   declareVariableWithType int, 42
 
 
 Overload resolution can be further influenced by constraining the set of
-types that will match the typedesc param:
+types that will match the type param:
 
 .. code-block:: nim
     :test: "nim c $1"
 
-  template maxval(T: typedesc[int]): int = high(int)
-  template maxval(T: typedesc[float]): float = Inf
+  template maxval(T: type int): int = high(int)
+  template maxval(T: type float): float = Inf
 
   var i = int.maxval
   var f = float.maxval
@@ -5578,7 +5576,35 @@ types that will match the typedesc param:
 
 The constraint can be a concrete type or a type class.
 
+type operator
+-------------
+
+You can obtain the type of a given expression by constructing a ``type``
+value from it (in many other languages this is known as the `typeof`:idx:
+operator):
+
+.. code-block:: nim
+  var x = 0
+  var y: type(x) # y has type int
+
+You may add a constraint to the resulting type to trigger a compile-time error
+if the expression doesn't have the expected type:
+
+.. code-block:: nim
+  var x = 0
+  var y: type[object](x) # Error: type mismatch: got <int> but expected 'object'
+
+If ``type`` is used to determine the result type of a proc/iterator/converter
+call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the
+interpretation where ``c`` is an iterator is preferred over the
+other interpretations:
+
+.. code-block:: nim
+  import strutils
 
+  # strutils contains both a ``split`` proc and iterator, but since an
+  # an iterator is the preferred interpretation, `y` has the type ``string``:
+  var y: type("a b c".split)
 
 
 Special Operators
@@ -7458,7 +7484,7 @@ Custom pragmas are defined using templates annotated with pragma ``pragma``:
 .. code-block:: nim
   template dbTable(name: string, table_space: string = "") {.pragma.}
   template dbKey(name: string = "", primary_key: bool = false) {.pragma.}
-  template dbForeignKey(t: typedesc) {.pragma.}
+  template dbForeignKey(t: type) {.pragma.}
   template dbIgnore {.pragma.}
 
 
diff --git a/doc/tut2.rst b/doc/tut2.rst
index 91cb52834..39e3bd89a 100644
--- a/doc/tut2.rst
+++ b/doc/tut2.rst
@@ -618,9 +618,9 @@ Turning the ``log`` proc into a template solves this problem:
   log("x has the value: " & $x)
 
 The parameters' types can be ordinary types or the meta types ``untyped``,
-``typed``, or ``typedesc``.
-``typedesc`` stands for *type description*, and ``untyped`` means symbol lookups and
-type resolution is not performed before the expression is passed to the template.
+``typed``, or ``type``. ``type`` suggests that only a type symbol may be given
+as an argument, and ``untyped`` means symbol lookups and type resolution is not
+performed before the expression is passed to the template.
 
 If the template has no explicit return type,
 ``void`` is used for consistency with procs and methods.