⬆️ ⬇️

Generics and Converters in Nim

Nim logo


Hello! In this article I will try to tell you what generic procedures and converters in Nim are (and show examples of their use).



What is Nim? Nim is a compiled (in C, C ++, Objective C and JS) high-level programming language with a garbage collector that has three main objectives (in order of priority): performance, expressiveness, elegance. The official site of the language , the repository on GitHub .

Also in Nim metaprogramming is well developed (generics, templates, macros).



First, I will show you what a procedure looks like, which has one argument of type int, and also returns an int:



proc plusOne(arg: int): int = return arg + 1 echo plusOne(5) #  6 


As I think, everything is very clear here (we add the number 1 to the arg argument of the int type and return the result)

')

Generics in Nim are procedures that can take several types (the compiler will make a separate version of the procedure for each type that was used with this procedure).



1 example - the usual generic



This example displays the length of an object if there is a len procedure for this object (almost the full equivalent of __len__ in Python):



 proc tryLen[T](something: T) = when compiles(something.len): # something.len   ,  len(something) echo something.len else: echo "      `len`" #    ,      `len` (     ) type MyObject = object #    let myObj = MyObject() tryLen([1, 2, 3]) #  3 tryLen("Hello world!") #  12 tryLen(myObj) #  "      `len`" 


This example is much more complicated than the previous one, I will try to briefly explain what is happening here:



To begin with, we declare the tryLen procedure itself, which takes an argument something like type T (T is the most commonly used name for an undefined type, instead of T you can write abcd, and everything will work the same way).



Then we use the special condition when compiles (this is an analogue of if, but the condition must be known at compile time, and when itself does not fall into the compiled code). If this condition is fulfilled for the given type, then we print the result of the len procedure for the given argument; if not, then we output the message.



Then we create an object of type MyObject, and apply tryLen to the array [1, 2, 3], the string “Hello world!”, And our object.



2 example - converter



It serves for the implicit conversion of one type to another (but it is not particularly welcomed by the developers of the language, since in this case it is still “explicit better than implicit”).



In this example, we will make a converter that converts our type of MyObject object into a number (in this case, just 1):



 type MyObject = object let myObj = MyObject() #     ,        return #     -   converter toInt(b: MyObject): int = 1 #     (       ) echo myObj.toInt + 1 #  2 #      : echo myObj + 1 #   2,   toInt   myObj   1 


The use of converters is a controversial topic (they are almost never used in the standard language library), but I treat them neutrally.



The latest example is a generic converter.



Yes, it sounds scary, but in fact everything is not so difficult. With it, we can make Nim a bit more like Python (namely, implicitly convert some types to bool)



 converter toBool[T](arg: T): bool = #        len when compiles(arg.len): arg.len > 0 #       `>` elif compiles(arg > 0): arg > 0 #  - ,   - nil else: not arg.isNil() if [1, 2, 3]: #   echo "True!" if @[1, 2, 3]: #   echo "True too!" if "": #   echo "No :(" if 5: # Integer echo "Nice number!" if 0.0001: # Float echo "Floats are nice too!" #      int (   ) var a: ref int if a: echo "False! nil!" 


Thank you for reading! I hope that you could learn something new for yourself.



Sources
Manual

Wikipedia

As well as users of Nim, which prompted me to solve various problems.

Source: https://habr.com/ru/post/333702/



All Articles