diff options
Diffstat (limited to 'doc/manual.rst')
-rw-r--r-- | doc/manual.rst | 156 |
1 files changed, 91 insertions, 65 deletions
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.} |