Nim (programming language)
Nim is a general-purpose, multi-paradigm, statically typed, compiled high-level system programming language,[9] designed and developed by a team around Andreas Rumpf. Nim is designed to be "efficient, expressive, and elegant",[10] supporting metaprogramming, functional, message passing,[11] procedural, and object-oriented programming styles by providing several features such as compile time code generation, algebraic data types, a foreign function interface (FFI) with C, C++, Objective-C, and JavaScript, and supporting compiling to those same languages as intermediate representations. DescriptionNim is statically typed.[12] It supports compile-time metaprogramming features such as syntactic macros and term rewriting macros.[13] Term rewriting macros enable library implementations of common data structures, such as bignums and matrices, to be implemented efficiently and with syntactic integration, as if they were built-in language facilities.[14] Iterators are supported and can be used as first class entities,[13] as can functions, allowing for the use of functional programming methods. Object-oriented programming is supported by inheritance and multiple dispatch. Functions can be generic and overloaded, and generics are further enhanced by Nim's support for type classes. Operator overloading is also supported.[13] Nim includes multiple tunable memory management strategies, including tracing garbage collection, reference counting, and fully manual systems, with the default being deterministic reference counting with optimizations via move semantics and cycle collection via trial deletion.[15]
As of August 2023[update], Nim compiles to C, C++, JavaScript, Objective-C,[17] and LLVM.[18] History
Andreas Rumpf is the designer and original implementer of Nim. He received a diploma in computer science from the University of Kaiserslautern-Landau, Germany. His research interests include hard realtime systems, embedded systems, compiler construction and artificial intelligence.[20] Nim's original website design by Dominik Picheta and Hugo Locurcio. Joseph Wecker created the Nim logo. The Nim programming language is a concise, fast programming language that compiles to C, C++ and JavaScript. Nim's initial development was started in 2005 by Andreas Rumpf. It was originally named Nimrod when the project was made public in 2008.[21]: 4–11 The first version of the Nim compiler was written in Pascal using the Free Pascal compiler.[22] In 2008, a version of the compiler written in Nim was released.[23] The compiler is free and open-source software, and is being developed by a community of volunteers working with Andreas Rumpf.[24] The language was officially renamed from Nimrod to Nim with the release of version 0.10.2 in December 2014.[25] On September 23, 2019, version 1.0 of Nim was released, signifying the maturing of the language and its toolchain. On August 1, 2023, version 2.0 of Nim was released, signifying the completion, stabilization of, and switch to the ARC/ORC memory model.[26] Language designSyntaxThe syntax of Nim resembles that of Python.[27] Code blocks and nesting statements are identified through use of whitespace, according to the offside-rule. Many keywords are identical to their Python equivalents, which are mostly English keywords, whereas other programming languages usually use punctuation. With the goal of improving upon its influence languages, even though Nim supports indentation-based syntax like Python, it introduced additional flexibility. For example, a single statement may span multiple lines if a comma or binary operator is at the end of each line. Nim also supports user-defined operators. Unlike Python, Nim implements (native) static typing. Nim's type system allows for easy type conversion, casting, and provides syntax for generic programming. Nim notably provides type classes which can stand in for multiple types, and provides several such type classes 'out of the box'. Type classes allow working with several types as if they were a single type. For example:
This code sample demonstrates the use of typeclasses in Nim: # Let's declare a function that takes any type of number and displays its double
# In Nim functions with side effect are called "proc"
proc timesTwo(i: SomeNumber) =
echo i * 2
# Let's write another function that takes any ordinal type, and returns
# the double of the input in its original type, if it is a number;
# or returns the input itself otherwise.
# We use a generic Type(T), and precise that it can only be an Ordinal
func twiceIfIsNumber[T: SomeOrdinal](i: T): T =
when T is SomeNumber: # A `when` is an `if` evaluated during compile time
result = i * 2 # You can also write `return i * 2`
else:
# If the Ordinal is not a number it is converted to int,
# multiplied by two, and reconverted to its based type
result = (i.int * 2).T
InfluenceAccording to the language creator, Nim was conceived to combine the best parts of Ada typing system, Python flexibility, and powerful Lisp macro system.[28] Nim was influenced by specific characteristics of existing languages, including the following:
Uniform function call syntaxNim supports uniform function call syntax (UFCS)[29] and identifier equality, which provides a large degree of flexibility in use. For example, each of these lines print "hello world", just with different syntax: echo "hello world"
echo("hello world")
"hello world".echo()
"hello world".echo
echo("hello", " world")
"hello".echo(" world")
"hello".echo " world"
Identifier equalityNim is almost fully style-insensitive; two identifiers are considered equal if they only differ by capitalization and underscores, as long as the first characters are identical. This is to enable a mixture of styles across libraries: one user can write a library using snake_case as a convention, and it can be used by a different user in a camelCase style without issue.[30] const useHttps = true
assert useHttps == useHttps
assert useHTTPS == useHttps
assert use_https == useHttps
StroppingThe stropping feature allows the use of any name for variables or functions, even when the names are reserved words for keywords. An example of stropping is the ability to define a variable named type Type = object
`int`: int
let `object` = Type(`int`: 9)
assert `object` is Type
assert `object`.`int` == 9
var `var` = 42
let `let` = 8
assert `var` + `let` == 50
const `assert` = true
assert `assert`
CompilerThe Nim compiler emits fast, optimized C code by default. It defers compiling-to-object code to an external C compiler[32] to leverage existing compiler optimization and portability. Many C compilers are supported, including Clang, Microsoft Visual C++ (MSVC), MinGW, and GNU Compiler Collection (GCC). The Nim compiler can also emit C++, Objective-C, and JavaScript code to allow easy interfacing with application programming interfaces (APIs) written in those languages;[9] developers can simply write in Nim, then compile to any supported language. This also allows writing applications for iOS and Android. There is also an unofficial LLVM backend, allowing use of the Nim compiler in a stand-alone way.[18] The Nim compiler is self-hosting, meaning it is written in the Nim language.[33] The compiler supports cross-compiling, so it is able to compile software for any of the supported operating systems, no matter the development machine. This is useful for compiling applications for embedded systems, and for uncommon and obscure computer architectures.[citation needed] Compiler optionsBy default, the Nim compiler creates a debug build.[34]
With the option Memory managementNim supports multiple memory management strategies, including the following:[35]
As of Nim 2.0, ORC is the default GC.[26] Development toolsBundledMany tools are bundled with the Nim install package, including: NimbleNimble is the standard package manager used by Nim to package Nim modules.[38] It was initially developed by Dominik Picheta, who is also a core Nim developer. Nimble has been included as Nim's official package manager since Oct 27, 2015, the v0.12.0 release.[39] Nimble packages are defined by The list of packages is stored in a JavaScript Object Notation (JSON) file which is freely accessible in the nim-lang/packages repository on GitHub. This JSON file provides Nimble with a mapping between the names of packages and their Git or Mercurial repository URLs. Nimble comes with the Nim compiler. Thus, it is possible to test the Nimble environment by running:
c2nimc2nim is a source-to-source compiler (transcompiler or transpiler) meant to be used on C/C++ headers to help generate new Nim bindings.[40] The output is human-readable Nim code that is meant to be edited by hand after the translation process. kochkoch is a maintenance script that is used to build Nim, and provide HTML documentation.[41] nimgrepnimgrep is a generic tool for manipulating text. It is used to search for regex, peg patterns, and contents of directories, and it can be used to replace tasks. It is included to assist with searching Nim's style-insensitive identifiers.[42] nimsuggestnimsuggest is a tool that helps any source code editor query a niminstniminst is a tool to generate an installer for a Nim program.[44] It creates .msi installers for Windows via Inno Setup, and install and uninstall scripts for Linux, macOS, and Berkeley Software Distribution (BSD). nimprettynimpretty is a source code beautifier, used to format code according to the official Nim style guide.[45] TestamentTestament is an advanced automatic unit tests runner for Nim tests. Used in developing Nim, it offers process isolation tests, generates statistics about test cases, supports multiple targets and simulated Dry-Runs, has logging, can generate HTML reports, can skip tests from a file, and more. Other notable toolsSome notable tools not included in the Nim distribution include: choosenimchoosenim was developed by Dominik Picheta, creator of the Nimble package manager, as a tool to enable installing and using multiple versions of the Nim compiler. It downloads any Nim stable or development compiler version from the command line, enabling easy switching between them.[46] nimpynimpy is a library that enables convenient Python integration in Nim programs.[47] pixiepixie is a feature-rich 2D graphics library, similar to Cairo or the Skia. It uses SIMD acceleration to speed-up image manipulation drastically. It supports many image formats, blending, masking, blurring, and can be combined with the boxy library to do hardware accelerated rendering. nimteropnimterop is a tool focused on automating the creation of C/C++ wrappers needed for Nim's foreign function interface.[48] LibrariesPure/impure librariesPure libraries are modules written in Nim only. They include no wrappers to access libraries written in other programming languages. Impure libraries are modules of Nim code which depend on external libraries that are written in other programming languages such as C. Standard libraryThe Nim standard library includes modules for all basic tasks, including:[49]
Use of other librariesA Nim program can use any library which can be used in a C, C++, or JavaScript program. Language bindings exist for many libraries, including GTK,[50][51] Qt QML,[52] wxWidgets,[53] SDL 2,[54][55] Raylib,[56] Godot,[57] UE5,[58] Cairo,[59] OpenGL,[60] Vulkan,[61] WinAPI,[62] zlib, libzip, OpenSSL and cURL.[63] Nim works with PostgreSQL, MySQL, and SQLite databases. There are open source tools of various degree of support that can be used to interface Nim with Lua,[64] Julia,[65] Rust,[66] C#,[67] and Python[68] programming languages or transpile Nim to TypeScript.[69] ExamplesHello worldThe "Hello, World!" program in Nim: echo("Hello, World!")
# Procedures can be called with no parentheses
echo "Hello, World!"
Another version of "Hello World" can be accomplished by calling the stdout.write("Hello, World!\n")
write(stdout, "Hello, World!\n")
FibonacciSeveral implementations of the Fibonacci function, showcasing implicit returns, default parameters, iterators, recursion, and while loops: proc fib(n: Natural): Natural =
if n < 2:
return n
else:
return fib(n-1) + fib(n-2)
func fib2(n: int, a = 0, b = 1): int =
if n == 0: a else: fib2(n-1, b, a+b)
iterator fib3: int =
var a = 0
var b = 1
while true:
yield a
swap a, b
b += a
FactorialProgram to calculate the factorial of a positive integer using the iterative approach, showcasing try/catch error handling and for loops: import std/strutils
var n = 0
try:
stdout.write "Input positive integer number: "
n = stdin.readline.parseInt
except ValueError:
raise newException(ValueError, "You must enter a positive number")
var fact = 1
for i in 2..n:
fact = fact * i
echo fact
Using the module math from Nim's standard library: import std/math
echo fac(x)
Reversing a stringA simple demonstration showing the implicit result variable and the use of iterators. proc reverse(s: string): string =
for i in countdown(s.high, 0):
result.add s[i]
let str1 = "Reverse This!"
echo "Reversed: ", reverse(str1)
One of Nim's more exotic features is the implicit Graphical user interfaceUsing GTK 3 with GObject introspection through the gintro module: import gintro/[gtk, glib, gobject, gio]
proc appActivate(app: Application) =
let window = newApplicationWindow(app)
window.title = "GTK3 application with gobject introspection"
window.defaultSize = (400, 400)
showAll(window)
proc main =
let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate)
discard run(app)
main()
This code requires the gintro module to work, which is not part of the standard library. To install the module gintro and many others you can use the tool nimble, which comes as part of Nim. To install the gintro module with nimble you do the following: nimble install gintro Programming paradigmsFunctional programmingFunctional programming is supported in Nim through first-class functions and code without side effects via the Contrary to purely functional programming languages, Nim is a multi-paradigm programming language, so functional programming restrictions are opt-in on a function-by-function basis. First-class functions
Nim supports first-class functions by allowing functions to be stored in variables or passed anonymously as parameters to be invoked by other functions.[72] The import std/[sequtils, sugar]
let powersOfTwo = @[1, 2, 4, 8, 16, 32, 64, 128, 256]
proc filter[T](s: openArray[T], pred: T -> bool): seq[T] =
result = newSeq[T]()
for i in 0 ..< s.len:
if pred(s[i]):
result.add(s[i])
echo powersOfTwo.filter(proc (x: int): bool = x > 32)
# syntactic sugar for the above, provided as a macro from std/sugar
echo powersOfTwo.filter(x => x > 32)
proc greaterThan32(x: int): bool = x > 32
echo powersOfTwo.filter(greaterThan32)
Side effectsSide effects of functions annotated with the
Function compositionUniform function call syntax allows the chaining of arbitrary functions, perhaps best exemplified with the import std/[sequtils, sugar]
let numbers = @[1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1]
# a and b are special identifiers in the foldr macro
echo numbers.filter(x => x > 3).deduplicate.foldr(a + b) # 30
Algebraic data types and pattern matching
Nim has support for product types via the import std/tables
type
Value = uint64
Ident = string
ExprKind = enum
Literal, Variable, Abstraction, Application
Expr = ref object
case kind: ExprKind
of Literal:
litIdent: Value
of Variable:
varIdent: Ident
of Abstraction:
paramAbs: Ident
funcAbs: Expr
of Application:
funcApp, argApp: Expr
func eval(expr: Expr, context: var Table[Ident, Value]): Value =
case expr.kind
of Literal:
return expr.litIdent
of Variable:
return context[expr.varIdent]
of Application:
case expr.funcApp.kind
of Abstraction:
context[expr.funcApp.paramAbs] = expr.argApp.eval(context)
return expr.funcAbs.eval(context)
else:
raise newException(ValueError, "Invalid expression!")
else:
raise newException(ValueError, "Invalid expression!")
Object-oriented programmingDespite being primarily an imperative and functional language, Nim supports various features for enabling object-oriented paradigms.[78][79] Subtyping and inheritance
Nim supports limited inheritance by use of type Animal = ref object of RootObj
name: string
age: int
type Dog = ref object of Animal
type Cat = ref object of Animal
var animals: seq[Animal] = @[]
animals.add(Dog(name: "Sparky", age: 10))
animals.add(Cat(name: "Mitten", age: 10))
for a in animals:
assert a of Animal
Subtyping relations can also be queried with the Method calls and encapsulationNim's uniform function call syntax enables calling ordinary functions with syntax similar to method call invocations in other programming languages. This is functional for "getters": and Nim also provides syntax for the creation of such "setters" as well. Objects may be made public on a per-field basis, providing for encapsulation. type Socket* = ref object
host: int # private, lacks export marker
# getter of host address
proc host*(s: Socket): int = s.host
# setter of host address
proc `host=`*(s: var Socket, value: int) =
s.host = value
var s: Socket
new s
assert s.host == 0 # same as host(s), s.host()
s.host = 34 # same as `host=`(s, 34)
Dynamic dispatchStatic dispatch is preferred, more performant, and standard even among method-looking routines.[79] Nonetheless, if dynamic dispatch is so desired, Nim provides the import std/strformat
type
Person = ref object of RootObj
name: string
Student = ref object of Person
Teacher = ref object of Person
method introduce(a: Person) =
raise newException(CatchableError, "Method without implementation override")
method introduce(a: Student) =
echo &"I am a student named {a.name}!"
method introduce(a: Teacher) =
echo &"I am a teacher named {a.name}!"
let people: seq[Person] = @[Teacher(name: "Alice"), Student(name: "Bob")]
for person in people:
person.introduce()
MetaprogrammingTemplatesNim supports simple substitution on the abstract syntax tree via its templates. template genType(name, fieldname: untyped, fieldtype: typedesc) =
type
name = object
fieldname: fieldtype
genType(Test, foo, int)
var x = Test(foo: 4566)
echo(x.foo) # 4566
The GenericsNim supports both constrained and unconstrained generic programming.
Generics may be used in procedures, templates and macros. Unconstrained generic identifiers ( proc addThese[T](a, b: T): T = a + b
echo addThese(1, 2) # 3 (of int type)
echo addThese(uint8 1, uint8 2) # 3 (of uint8 type)
# we don't want to risk subtracting unsigned numbers!
proc subtractThese[T: SomeSignedInt | float](a, b: T): T = a - b
echo subtractThese(1, 2) # -1 (of int type)
import std/sequtils
# constrained generics can also be directly on the parameters
proc compareThese[T](a, b: string | seq[T]): bool =
for (i, j) in zip(a, b):
if i != j:
return false
One can further clarify which types the procedure will accept by specifying a type class (in the example above, MacrosMacros can rewrite parts of the code at compile-time. Nim macros are powerful and can operate on the abstract syntax tree before or after semantic checking.[82] Here's a simple example that creates a macro to call code twice: import std/macros
macro twice(arg: untyped): untyped =
result = quote do:
`arg`
`arg`
twice echo "Hello world!"
The echo "Hello world!"
echo "Hello world!"
Foreign function interface (FFI)Nim's FFI is used to call functions written in the other programming languages that it can compile to. This means that libraries written in C, C++, Objective-C, and JavaScript can be used in the Nim source code. One should be aware that both JavaScript and C, C++, or Objective-C libraries cannot be combined in the same program, as they are not as compatible with JavaScript as they are with each other. Both C++ and Objective-C are based on and compatible with C, but JavaScript is incompatible, as a dynamic, client-side web-based language.[21]: 226 The following program shows the ease with which external C code can be used directly in Nim. proc printf(formatstr: cstring) {.header: "<stdio.h>", varargs.}
printf("%s %d\n", "foo", 5)
In this code the Basic example using 'console.log' directly for the JavaScript compiling target: proc log(args: any) {.importjs: "console.log(@)", varargs.}
log(42, "z", true, 3.14)
The JavaScript code produced by the Nim compiler can be executed with Node.js or a web browser. Parallelism
To activate threading support in Nim, a program should be compiled with import std/locks
var
thr: array[0..4, Thread[tuple[a,b: int]]]
L: Lock
proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
for i in interval.a..interval.b:
acquire(L) # lock stdout
echo i
release(L)
initLock(L)
for i in 0..high(thr):
createThread(thr[i], threadFunc, (i*10, i*10+5))
joinThreads(thr)
Nim also has a import std/os
type
CalculationTask = object
id*: int
data*: int
CalculationResult = object
id*: int
result*: int
var task_queue: Channel[CalculationTask]
var result_queue: Channel[CalculationResult]
proc workerFunc() {.thread.} =
result_queue.open()
while true:
var task = task_queue.recv()
result_queue.send(CalculationResult(id: task.id, result: task.data * 2))
var workerThread: Thread[void]
createThread(workerThread, workerFunc)
task_queue.open()
task_queue.send(CalculationTask(id: 1, data: 13))
task_queue.send(CalculationTask(id: 2, data: 37))
while true:
echo "got result: ", repr(result_queue.recv())
Concurrency
Asynchronous IO is supported either via the import std/[asynchttpserver, asyncdispatch]
# chronos could also be alternatively used in place of asyncdispatch,
# with no other changes.
var server = newAsyncHttpServer()
proc cb(req: Request) {.async.} =
await req.respond(Http200, "Hello World")
waitFor server.serve(Port(8080), cb)
CommunityOnlineNim has an active community on the self-hosted, self-developed official forum.[84] Further, the project uses a Git repository, bug tracker, RFC tracker, and wiki hosted by GitHub, where the community engages with the language.[85] There are also official online chat rooms, bridged between IRC, Matrix, Discord, Gitter, and Telegram.[86] ConventionsThe first Nim conference, NimConf, took place on June 20, 2020. It was held digitally due to COVID-19, with an open call for contributor talks in the form of YouTube videos.[87] The conference began with language overviews by Nim developers Andreas Rumpf and Dominik Picheta. Presentation topics included talks about web frameworks, mobile development, Internet of things (IoT) devices, and game development, including a talk about writing Nim for Game Boy Advance.[88] NimConf 2020 is available as a YouTube playlist.[89] NimConf 2021 occurred the following year, was also held digitally, and included talks about game development, REPLs, real-time operating systems, Nim in the industry, object-relational mapping (ORM), fuzzing, language design, and graphics libraries.[90] In addition to official conferences, Nim has been featured at various other conventions. A presentation on Nim was given at the O'Reilly Open Source Convention (OSCON) in 2015.[91][92][93] Four speakers represented Nim at FOSDEM 2020, including the creator of the language, Andreas Rumpf.[94] At FOSDEM 2022, Nim hosted their own developer room virtually due to the COVID-19 pandemic.[95] Talks were held on concurrency, embedded programming, programming for GPUs, entity-component systems, game development, rules engines, Python interop, and metaprogramming.[96] See alsoReferences
External links
|
Portal di Ensiklopedia Dunia