Nimは、汎用、マルチパラダイム、静的型付け、コンパイル型、高水準のシステムプログラミング言語です。[ 9 ]これは、Andreas Rumpf が率いるチームによって設計および開発されました。Nim は「効率的、表現力豊か、かつエレガント」であることを目指しており、[ 10 ]メタプログラミング、関数型プログラミング、メッセージパッシング、[ 11 ]手続き型プログラミング、オブジェクト指向プログラミングのパラダイムをサポートしています。Nim には、コンパイル時のコード生成、代数的データ型、C、C++、Objective-C、JavaScriptとインターフェースするための外部関数インターフェース(FFI) などの機能が含まれています。また、中間表現としてこれらの言語へのコンパイルもサポートしています。
Nim は静的型付け言語です。[ 12 ]構文マクロや項書き換えマクロなどのコンパイル時メタプログラミング機能をサポートしています。[ 13 ]項書き換えマクロを使用すると、多倍長整数や行列などの一般的なデータ構造のライブラリ実装を、組み込み言語機能であるかのように、効率的かつ構文的に統合して実装できます。[ 14 ]イテレータはサポートされており、第一級エンティティとして使用できます。[ 13 ]関数も同様で、関数型プログラミング手法を使用できます。オブジェクト指向プログラミングは、継承と多重ディスパッチによってサポートされています。関数はジェネリックおよびオーバーロードでき、ジェネリックはNim の型クラスのサポートによってさらに強化されます。演算子オーバーロードもサポートされています。[ 13 ] Nim には、トレースガベージコレクション、参照カウント、完全手動システムなど、調整可能な複数のメモリ管理戦略が含まれており、デフォルトは、ムーブセマンティクスによる最適化と試行削除によるサイクルコレクションを備えた決定論的参照カウントです。[ 15 ]
[Nim]は、 PascalとPythonをまたいでCコードまたはJavaScriptにコンパイルされる、非常に独創的な設計を提示している。 [ 16 ]
—アンドリュー・ビンストック、ドクター・ドブス・ジャーナル編集長、2014年
2023年8月現在 NimはC、C++、JavaScript、Objective-C [ 17 ]、およびLLVM [ 18 ]にコンパイルされます。
Andreas Rumpf は Nim の設計者であり、オリジナルの実装者です。彼はドイツのカイザースラウテルン工科大学でコンピュータサイエンスの学位を取得しました。彼の研究分野は、ハードリアルタイムシステム、組み込みシステム、コンパイラ構築、人工知能などです。[ 20 ]
Nimの初期開発は2005年にNimrodという名前で開始され、2008年に公開された。[ 21 ]: 4-11
Nimコンパイラの最初のバージョンは、Free Pascalコンパイラを使用してPascalで書かれました。[ 22 ] 2008 年に、Nim で書かれたコンパイラのバージョンがリリースされました。[ 23 ]このコンパイラはフリーでオープンソースのソフトウェアであり、Andreas Rumpf と協力するボランティアのコミュニティによって開発されています。[ 24 ] 2014 年 12 月にバージョン 0.10.2 がリリースされたときに、言語は正式にNimrodからNimに改名されました。 [ 25 ] 2019 年 9 月 23 日に、言語とそのツールチェーンの成熟を示す Nim のバージョン 1.0 がリリースされました。2023 年 8 月 1 日に、ARC/ORC メモリ モデルの完成、安定化、および切り替えを示す Nim のバージョン 2.0 がリリースされました。[ 26 ]
Nim の構文はPythonの構文に似ています。[ 27 ]コード ブロックとネストされたステートメントは、オフサイド ルールに従って空白を使用して識別されます。多くのキーワードはPython の同等のキーワードと同一で、それらは主に英語のキーワードですが、他のプログラミング言語では通常句読点が使用されます。Nim は、影響を受けた言語を改善することを目的として、 Python のようにインデントベースの構文をサポートしているにもかかわらず、追加の柔軟性を導入しました。たとえば、各行の末尾にカンマまたは二項演算子がある場合、単一のステートメントが複数行にまたがる可能性があります。Nim はユーザー定義の演算子もサポートしています。
Pythonとは異なり、Nimは(ネイティブの)静的型付けを実装しています。Nimの型システムは、型変換やキャストを容易にし、汎用プログラミングのための構文を提供します。特にNimは、複数の型を代用できる型クラスを提供しており、そのような型クラスのいくつかはすぐに使用できます。型クラスを使用すると、複数の型を単一の型であるかのように扱うことができます。例:
openarray–さまざまなサイズ、シーケンス、文字列の配列を表しますSomeSignedInt–すべての符号付き整数型を表しますSomeInteger–符号付きか符号なしかに関わらず、すべての整数型を表しますSomeOrdinal–整数以外のすべての基本的な可算型と順序付き型を表しますこのコードサンプルは、Nimにおける型クラスの使用方法を示しています。
# 任意の型の数値を受け取り、その倍数を表示する関数を宣言します。# Nim では、副作用のある関数は「proc」と呼ばれます。proc timesTwo ( i : SomeNumber ) = echo i * 2# 任意の序数型を受け取り、それが数値であれば入力の2倍を元の型で返し、そうでなければ入力自体を返す別の関数を記述しましょう。# 汎用型 Type(T) を使用し、それが Ordinal 型のみであることを明示します。func twiceIfIsNumber [ T : SomeOrdinal ] ( i : T ): T = when T is SomeNumber : # `when` はコンパイル時に評価される `if` ですresult = i * 2 # `return i * 2` と記述することもできますelse : # Ordinal が数値でない場合は、int 型に変換され、# 2 倍され、元の型に再変換されますresult = ( i . int * 2 ). TechotwiceIfIsNumber(67)# Passes an int to the functionecho twiceIfIsNumber(67u8) # Passes an uint8echotwiceIfIsNumber(true)# Passes a bool (Which is also an Ordinal)
言語開発者によると、NimはAdaの型システム、Pythonの柔軟性、強力なLispマクロシステムの最良の部分を組み合わせるために考案されたとのことです。[ 28 ]
ニムは、以下のような既存言語の特定の特性から影響を受けている。
Nimは統一関数呼び出し構文(UFCS)[ 29 ]と識別子の等価性をサポートしており、使用において高い柔軟性を提供します。
例えば、以下の各行はそれぞれ「hello world」と出力しますが、構文が異なります。
echo "hello world" echo ( "hello world" ) "hello world" . echo () "hello world" . echo echo ( "hello" , " world" ) "hello" . echo ( " world" ) "hello" . echo " world"Nim はほぼ完全にスタイルに依存しません。最初の文字が同じであれば、大文字とアンダースコアのみが異なる2つの識別子は等しいとみなされます。これは、ライブラリ間でスタイルを混在させるためです。あるユーザーがスネークケースを慣例としてライブラリを作成し、別のユーザーがそれをキャメルケーススタイルで使用しても問題ありません。[ 30 ]
const useHttps = true assert useHttps == useHttps assert useHTTPS == useHttps assert use_https == useHttpsストロッピング機能により、変数や関数に任意の名前を使用できます。たとえその名前がキーワードの予約語でifあってもです。ストロッピングの例としては、キーワードと衝突することなく、という名前の変数を定義できることが挙げられますif。Nim では、バッククォートを使用してこの機能を実現しており、任意の予約語を識別子として使用できます。[ 31 ]
型Type = object ` int `: intlet ` object` = Type ( ` int` : 9 ) assert ` object` is Type assert ` object`.`int` == 9var ` var ` = 42 let ` let ` = 8アサート` var ` + ` let ` == 50const ` assert ` = true assert ` assert `Nim コンパイラは、デフォルトで高速で最適化された C コードを生成します。既存のコンパイラの最適化と移植性を活用するために、オブジェクト コードへのコンパイルを外部の C コンパイラに委ねます [ 32 ]。Clang、Microsoft Visual C++ (MSVC)、MinGW、GNU Compiler Collection (GCC) など、多くの C コンパイラがサポートされています。Nimコンパイラは、 C ++、Objective - C 、 JavaScriptコードも生成できるため、これらの言語で記述されたアプリケーション プログラミング インターフェイス ( API )とのインターフェースが容易になります[ 9 ]。開発者は、Nim で記述し、サポートされている任意の言語にコンパイルするだけで済みます。これにより、iOSおよびAndroid用のアプリケーションを作成することもできます。非公式のLLVMバックエンドもあり、Nim コンパイラをスタンドアロンで使用できます[ 18 ] 。
Nimコンパイラは自己ホスト型であり、Nim言語で記述されています。[ 33 ]このコンパイラはクロスコンパイルをサポートしているため、開発マシンに関係なく、サポートされているオペレーティングシステムのいずれに対してもソフトウェアをコンパイルできます。これは、組み込みシステムや、一般的でない、あるいはあまり知られていないコンピュータアーキテクチャ向けのアプリケーションをコンパイルする場合に役立ちます。
デフォルトでは、Nim コンパイラはデバッグビルドを作成します。[ 34 ] オプションを使用すると、速度が最適化され、ランタイム チェックが少ないリリース-d:releaseビルドを作成できます。 [ 34 ] オプションを使用すると、最大限の速度が必要な場合は、すべてのランタイム チェックを無効にできます。[ 34 ]-d:danger
Nimは、以下を含む複数のメモリ管理戦略をサポートしています。[ 35 ]
--mm:arc–ムーブセマンティクス最適化による自動参照カウント(ARC)は、共有ヒープを提供します。ハードリアルタイムシステムに対して完全に決定論的なパフォーマンスを提供します。[ 36 ]参照サイクルはメモリリークを引き起こす可能性があります。これらは、プラグマを手動で注釈するか、を使用することで対処できます。{.acyclic.}--mm:orc--mm:orc– と同様だ--mm:arcが、「試行削除」に基づくサイクルコレクター(「O」)を追加する。[ 37 ]サイクルコレクターは、潜在的に循環的である場合にのみ型を分析する。--mm:refc標準的な遅延参照カウント方式のガベージコレクタと、サイクルを回収するためのシンプルなマークアンドスイープ方式のバックアップGCを備えています。ヒープはスレッドローカルです。--mm:markAndSweep– シンプルなマークアンドスイープ方式のガベージコレクタ。ヒープはスレッドローカルです。--mm:boehm–ベームベースのガベージコレクタであり、共有ヒープを提供します。--mm:go– Goのガベージコレクタ。Goとの相互運用性に役立ちます。共有ヒープを提供します。--mm:noneメモリ管理戦略もガベージコレクタもありません。割り当てられたメモリは、開発者のコードによって手動で解放されない限り、決して解放されません。Nim 2.0以降、ORCがデフォルトのGCです。[ 26 ]
Nimのインストールパッケージには、以下のような多くのツールが同梱されています。
Nimble は、Nim モジュールをパッケージ化するために Nim が使用する標準パッケージマネージャです。[ 38 ]当初は、コア Nim 開発者でもある Dominik Picheta によって開発されました。Nimble は、2015 年 10 月 27 日の v0.12.0 リリース以降、Nim の公式パッケージマネージャとして採用されています。[ 39 ]
Nimble パッケージは.nimble、パッケージのバージョン、作成者、ライセンス、説明、依存関係などの情報を含むファイルによって定義されます。[ 21 ] : 132これらのファイルは、NimScript と呼ばれる Nim 構文の限定されたサブセットをサポートしており、主な制限は FFI へのアクセスです。これらのスクリプトを使用すると、テスト手順を変更したり、カスタムタスクを記述したりできます。
パッケージの一覧は、GitHub の nim-lang/packages リポジトリで公開されている JavaScript Object Notation ( JSON ) ファイルに格納されています。この JSON ファイルは、パッケージ名とその Git または Mercurial リポジトリの URL とのマッピングを Nimble に提供します。
NimbleにはNimコンパイラが付属しています。そのため、以下のコマンドを実行することでNimble環境をテストできますnimble -v。このコマンドを実行すると、Nimbleのバージョン番号、コンパイル日時、およびGitハッシュが表示されます。NimbleはGitパッケージを使用しており、Nimbleが正しく機能するためにはGitパッケージが利用可能である必要があります。Nimbleコマンドラインは、モジュールパッケージのインストール、削除(アンインストール)、およびアップグレード(パッチ適用)を行うためのインターフェースとして使用されます。[ 21 ] : 130–131
c2nim は、C / C++ヘッダーに対して使用して新しい Nim バインディングを生成することを目的としたソース間コンパイラ(トランスコンパイラまたはトランスパイラ) です。 [ 40 ]出力は、翻訳処理後に手動で編集することを目的とした人間が読める Nim コードです。
koch は Nim をビルドし、HTML ドキュメントを提供するメンテナンス スクリプトです。[ 41 ]
nimgrep は、テキストを操作するための汎用ツールです。正規表現、ペグパターン、ディレクトリの内容を検索するために使用され、タスクの置換にも使用できます。Nim のスタイルに依存しない識別子の検索を支援するために含まれています。[ 42 ]
.nimnimsuggestは、ソースコードエディタがソースファイルを照会して、シンボルの定義や補完候補などの有用な情報を取得するのに役立つツールです。 [ 43 ]
niminst は Nim プログラムのインストーラを生成するツールです。[ 44 ] Inno Setup を介して Windows 用の .msi インストーラを作成し、 Linux、macOS、およびBerkeley Software Distribution (BSD) 用のインストールおよびアンインストール スクリプトを作成します。
nimprettyはソースコード整形ツールで、公式のNimスタイルガイドに従ってコードをフォーマットするために使用されます。[ 45 ]
Testamentは、Nimテスト用の高度な自動単体テストランナーです。Nim開発において、プロセス分離テスト、テストケースに関する統計情報の生成、複数ターゲットとシミュレートされたドライランのサポート、ログ記録機能、HTMLレポートの生成、ファイルからのテストのスキップなど、様々な機能を提供します。
Nimディストリビューションに含まれていない注目すべきツールには、以下のようなものがあります。
choosenim は、Nimble パッケージマネージャの作成者である Dominik Picheta によって、複数のバージョンの Nim コンパイラをインストールして使用できるようにするツールとして開発されました。コマンドラインから任意の Nim の安定版または開発版コンパイラをダウンロードし、それらを簡単に切り替えることができます。[ 46 ]
nimpyは、NimプログラムにPythonを簡単に統合できるライブラリです。[ 47 ]
pixieは、 CairoやSkiaに似た、機能豊富な2Dグラフィックスライブラリです。SIMDアクセラレーションを利用して画像処理を大幅に高速化します。多くの画像フォーマット、ブレンド、マスキング、ぼかしをサポートし、 boxyライブラリと組み合わせることでハードウェアアクセラレーションによるレンダリングも可能です。
nimteropは、Nimの外部関数インターフェースに必要なC/C++ラッパーの作成を自動化することに焦点を当てたツールです。[ 48 ]
純粋なライブラリとは、Nimのみで記述されたモジュールのことです。他のプログラミング言語で記述されたライブラリにアクセスするためのラッパーは含まれていません。
不純ライブラリとは、C言語などの他のプログラミング言語で書かれた外部ライブラリに依存するNimコードのモジュールのことです。
Nim 標準ライブラリには、以下を含むすべての基本タスクのモジュールが含まれています。[ 49 ]
Nim プログラムは、C、C++、または JavaScript プログラムで使用できるライブラリであればどれでも使用できます。GTK [ 50 ] [ 51 ] Qt QML [ 52 ] wxWidgets [ 53 ] SDL 2 [ 54 ] [ 55 ] Raylib [ 56 ] Godot [ 57 ] UE5 [ 58 ] Cairo [ 59 ] OpenGL [ 60 ] Vulkan [ 61 ] Windows API (WinAPI) [ 62 ] zlib、 libzip 、 OpenSSL 、 cURL [ 63 ]など、多くのライブラリの言語バインディングが存在します。Nimは、 PostgreSQL 、 MySQL 、 SQLiteのデータベースと連携します。
NimをLua [ 64 ] Julia [ 65 ] Rust [ 66 ] C# [ 67 ]およびPython [ 68 ] とインターフェースしたり、 NimをTypeScript [ 69 ]にトランスパイルしたりするために使用できる、さまざまなレベルのサポートを備えたオープンソースツールが存在 します。
Nimの「Hello, World!」プログラム:
echo ( "Hello, World!" ) # プロシージャは括弧なしで呼び出すことができますecho "Hello, World!"write「Hello World」の別のバージョンは、ストリームを使って関数を呼び出すことで実現できますstdout。
stdout.write ( "Hello, World! \n " ) write ( stdout , " Hello , World! \n " )暗黙的な戻り値、デフォルトパラメータ、イテレータ、再帰、およびwhileループを示す、フィボナッチ関数のいくつかの実装例:
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反復法を用いて正の整数の階乗を計算するプログラム。try/catchエラー処理とforループの使用例を示す。
import std / strutilsvar n = 0 try : stdout.write "正の整数を入力してください: " n = stdin.readline.parseInt except ValueError : raise newException ( ValueError , "正の数を入力してください" )var fact = 1 for i in 2 .. n : fact = fact * iエコーファクトNimの標準ライブラリのmathモジュールを使用する:
import std / math echo fac ( x )A simple demonstration showing the implicit result variable and the use of iterators.
procreverse(s:string):string=foriincountdown(s.high,0):result.adds[i]letstr1="Reverse This!"echo"Reversed: ",reverse(str1)One of Nim's more exotic features is the implicit result variable. Every procedure in Nim with a non-void return type has an implicit result variable that represents the value to be returned. In the for loop we see an invocation of countdown which is an iterator. If an iterator is omitted, the compiler will attempt to use an items iterator, if one is defined for the type specified.
Using GTK 3 with GObject introspection through the gintro module:
importgintro/[gtk,glib,gobject,gio]procappActivate(app:Application)=letwindow=newApplicationWindow(app)window.title="GTK3 application with gobject introspection"window.defaultSize=(400,400)showAll(window)procmain=letapp=newApplication("org.gtk.example")connect(app,"activate",appActivate)discardrun(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
Nim では、第一級関数と、プラグマまたはキーワードによる副作用のないコードを通じて関数型プログラミングがサポートされています。[ 70 ] Nim は、実験的な機能でコンパイルされたときに副作用を生成しない契約に従わないコードに対して副作用分析を実行し、コンパイルエラーを発生させます。この機能は、後のバージョンでデフォルトになる予定です。[ 71 ]noSideEffectfuncstrictFuncs
純粋な関数型プログラミング言語とは異なり、Nimはマルチパラダイムプログラミング言語であるため、関数型プログラミングの制約は関数ごとに個別に選択できます。
Nim は、関数を変数に格納したり、他の関数から呼び出されるパラメータとして匿名で渡したりできるようにすることで、第一級関数をサポートしています。 [ 72 ]このstd/sugarモジュールは、型宣言とインスタンス化における匿名関数の構文糖衣を提供します。
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 ) # 上記の構文糖衣。std/sugar からマクロとして提供されています。echo powersOfTwo.filter ( x = > x > 32 )proc greaterThan32 ( x : int ): bool = x > 32 echo powersOfTwo . filter ( greaterThan32 )プラグマで注釈が付けられた関数の副作用noSideEffectがチェックされ、コンパイラはそれらの条件を満たさない関数のコンパイルを拒否します。 Nim の副作用には、ミューテーション、グローバル状態へのアクセスまたは変更、非同期コード、スレッドコード、および IO が含まれます。varまたはref型のパラメータを受け取る関数では、パラメータのミューテーションが発生する可能性があります。これは、現在実験段階にあるstrictFuncs将来的にコンパイルに失敗すると予想されます。[ 73 ]キーワードは、プラグマfuncのショートカットを導入しますnoSideEffect。[ 74 ]
funcbinarySearch[T](a:openArray[T];elem:T):int
- は...の略です。
procbinarySearch[T](a:openArray[T];elem:T):int{.noSideEffect.} {.experimental: "strictFuncs".}typeNode=refobjectle,ri:Nodedata:stringfunclen(n:Node):int=# 有効: len には副作用がありませんvarit=nwhileit!=nil:incresultit=it.rifuncmut(n:Node)=letm=n# is the statement that connected the mutation to the parameterm.data="yeah"# the mutation is here# Error: 'mut' can have side effects# an object reachable from 'n' is potentially mutated
統一された関数呼び出し構文により、任意の関数を連鎖させることが可能になり、おそらくstd/sequtilsライブラリが最も良い例となっている。[ 75 ]
import std /[ sequtils , sugar ]let numbers = @[ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] # a と b は foldr マクロの特別な識別子ですecho numbers . filter ( x => x > 3 ). deduplicate . foldr ( a + b ) # 30Nim は、型を介して積型をサポートしobject、オブジェクト バリアントを介して和型をサポートしています。バリアントは、タグ付き共用体の生の表現であり、バリアントのフィールドにアクセスする前に安全にマッチングする必要がある列挙型タグが付いています。 [ 76 ]これらの型は代数的に合成できます。構造的パターン マッチングは利用可能ですが、さまざまなサードパーティ ライブラリのマクロに限定されています。[ 77 ]
import std / tablestype 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 : Exprfunc 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!" )Nimは主に命令型言語および関数型言語であるにもかかわらず、オブジェクト指向パラダイムを可能にするためのさまざまな機能をサポートしています。[ 78 ] [ 79 ]
ref objectsNim は、およびキーワードの使用により限定的な継承をサポートしていますof。[ 79 ]継承を有効にするには、初期 (「ルート」) オブジェクトはから継承する必要がありますRootObj。継承は慣用的な Nim コード内では限定的に使用されます。例外は例外です。[ 80 ]
type Animal = RootObjの参照オブジェクトname : string age : int type Dog = Animalの参照オブジェクトtype Cat = Animalの参照オブジェクトvar animals : seq [ Animal ] = @[] animals.add ( Dog ( name : " Sparky " , age : 10 ) ) animals.add ( Cat ( name : "Mitten" , age : 10 ) )動物の場合:動物のを主張するサブタイピング関係もキーワードで照会できますof。[ 79 ]
Nimの統一された関数呼び出し構文により、他のプログラミング言語のメソッド呼び出しと同様の構文で通常の関数を呼び出すことができます。これは「ゲッター」にも有効であり、Nimは「セッター」を作成するための構文も提供しています。オブジェクトはフィールドごとに公開することができ、カプセル化を実現します。
type Socket * = ref object host : int # プライベート、エクスポートマーカーなし# ホストアドレスの取得proc host * ( s : Socket ): int = s . host# ホストアドレスの設定proc `host=` * ( s : var Socket , value : int ) = s . host = valuevar s : Socket new s assert s . host == 0 # host(s)、s.host() と同じs . host = 34 # `host=`(s, 34) と同じ静的ディスパッチは、メソッドのようなルーチンの中でも、よりパフォーマンスが高く、標準的であるため、推奨されます。[ 79 ]ただし、動的ディスパッチが必要な場合は、Nim は参照型で動的ディスパッチをmethod有効にするためのキーワードを提供します。
import std / strformattype Person = RootObjの参照オブジェクトname : string Student = Personの参照オブジェクトTeacher = Personの参照オブジェクトmethod introduce ( a : Person ) = raise newException ( CatchableError , "実装オーバーライドのないメソッド" )メソッドintroduce ( a : Student ) = echo & "私は{a.name}という名前の学生です!"メソッドintroduce ( a : Teacher ) = echo & "私は {a.name} という名前の教師です!" let people : seq [ Person ] = @[ Teacher ( name : "Alice" ), Student ( name : "Bob" ) ] for person in people : person . introduce ()Nimは、テンプレートを介して抽象構文木上での単純な置換をサポートしています。
テンプレートgenType ( name , fieldname : untyped , fieldtype : typedesc ) = type name = object fieldname : fieldtypegenType ( Test 、foo 、int )var x = Test ( foo : 4566 ) echo ( x.foo ) # 4566これgenTypeはコンパイル時に呼び出され、Test型が作成されます。
Nim は、制約付きジェネリックプログラミングと制約なしジェネリックプログラミングの両方をサポートしています。ジェネリックは、プロシージャ、テンプレート、マクロで使用できます。制約なしジェネリック識別子 (Tこの例では) は、ルーチン名の後に角括弧で囲んで定義します。制約付きジェネリックは、ジェネリック識別子、またはパラメータに直接配置できます。
proc addThese [ T ] ( a , b : T ): T = a + b echo addThese ( 1 , 2 ) # 3 (int 型) echo addThese ( uint8 1 , uint8 2 ) # 3 (uint8 型)# 符号なし数値の減算は危険です!proc subtractThese [ T : SomeSignedInt | float ] ( a , b : T ): T = a - b echo subtractThese ( 1 , 2 ) # -1 (int 型)import std / sequtils# 制約付きジェネリクスはパラメータに直接指定することもできますproc compareThese [ T ] ( a , b : string | seq [ T ] ): bool = for ( i , j ) in zip ( a , b ): if i != j : return false型クラスを指定することで、手続きが受け入れる型をさらに明確にすることができます(上記の例では、SomeSignedInt)。[ 81 ]
マクロはコンパイル時にコードの一部を書き換えることができます。Nim マクロは強力で、意味チェックの前または後に抽象構文木に対して操作を行うことができます。[ 82 ]
コードを2回呼び出すマクロを作成する簡単な例を以下に示します。
import std / macrosマクロtwice ( arg : untyped ): untyped = result = quote do : ` arg ` ` arg `「ハローワールド!」を2回エコーします。 この例のマクロtwiceは、抽象構文木形式のecho文を入力として受け取ります。この例では、構文木に何の操作も加えずにそのまま返すことにしました。しかし、それを2回行うため、マクロ名が付けられています。結果として、コンパイル時にマクロによってコードが書き換えられ、次のコードのような形になります。
echo "こんにちは世界!" echo "こんにちは世界!"NimのFFIは、コンパイル可能な他のプログラミング言語で書かれた関数を呼び出すために使用されます。つまり、C、C++、Objective-C、JavaScriptで書かれたライブラリをNimのソースコードで使用できます。ただし、JavaScriptとC、C++、Objective-Cのライブラリは同じプログラム内で組み合わせることはできません。これらのライブラリはJavaScriptとの互換性が他のライブラリとの互換性ほど高くないためです。C++とObjective-CはどちらもCをベースとしており互換性がありますが、JavaScriptは動的なクライアントサイドのWebベース言語であるため互換性がありません。[ 21 ] : 226
以下のプログラムは、外部のCコードをNimで直接使用できる容易さを示しています。
proc printf ( formatstr : cstring ) {.header : "<stdio.h>", varargs.}printf ( "%s %d \n " , "foo" , 5 )このコードでは、printf関数がNimにインポートされ、その後使用されています。
JavaScriptコンパイル対象として「console.log」を直接使用する基本的な例:
proc log ( args : any ) {.importjs : "console.log(@)", varargs.} log ( 42 , "z" , true , 3.14 )Nimコンパイラによって生成されたJavaScriptコードは、Node.jsまたはWebブラウザで実行できます。
Nimでスレッドサポートを有効にするには、コマンドライン引数を指定してプログラムをコンパイルする必要があります--threads:on。各スレッドはそれぞれ独立したガベージコレクション対象のヒープを持ち、メモリの共有が制限されるため、効率が向上し、スレッド間の競合状態を防ぐことができます。
import std / locksvar thr : array [ 0 .. 4 , Thread [ tuple [ a , b : int ]]] L : Lockproc threadFunc ( interval : tuple [ a , b : int ] ) {.thread.} = for i in interval . a .. interval . b : acquire ( L ) # 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には、channelsスレッド間でデータを渡す作業を簡素化するモジュールも用意されている。
import std / ostype CalculationTask = object id * : int data * : intCalculationResult =オブジェクトid * : int result * : intvar 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 "結果を取得しました: " , repr ( result_queue.recv ( ) )asyncdispatch非同期I/Oは、標準ライブラリのモジュールまたは外部ライブラリのいずれかを介してサポートされますchronos。[ 83 ]どちらのライブラリも、特別な言語サポートを必要とせずに、マクロシステムを介してasync/await構文を追加します。非同期HTTPサーバーの例を以下に示します。
import std /[ asynchttpserver , asyncdispatch ] # chronos は、他の変更なしでasyncdispatch の代わりに代替として使用できます。var server = newAsyncHttpServer ( ) proc cb ( req : Request ) {.async.} = await req.respond ( Http200 , "Hello World " )server.serve ( Port ( 8080 ), cb )を待機します。Nim には、自己ホスト型で自己開発型の公式フォーラムに活発なコミュニティがあります。[ 84 ]さらに、このプロジェクトはGitHubでホストされている Git リポジトリ、バグトラッカー、RFC トラッカー、および wiki を使用しており、コミュニティはそこで言語について議論しています。[ 85 ]また、 IRC、Matrix、Discord、Gitter、およびTelegram を連携させた公式のオンラインチャット ルームもあります。[ 86 ]
Nim の最初のカンファレンスである NimConf は、2020 年 6 月 20 日に開催されました。COVID -19 の影響でデジタル形式で開催され、 YouTube動画の形式での貢献者による講演が公募されました。[ 87 ]カンファレンスは、Nim 開発者の Andreas Rumpf と Dominik Picheta による言語の概要説明から始まりました。プレゼンテーションのトピックには、Web フレームワーク、モバイル開発、モノのインターネット(IoT) デバイス、ゲーム開発に関する講演が含まれ、 Game Boy Advance用の Nim の記述に関する講演も含まれていました。[ 88 ] NimConf 2020 は YouTube のプレイリストとして利用可能です。[ 89 ] NimConf 2021 は翌年に開催され、これもデジタル形式で開催され、ゲーム開発、REPL、リアルタイム オペレーティングシステム、業界での Nim、オブジェクト リレーショナル マッピング(ORM)、ファジング、言語設計、グラフィックス ライブラリに関する講演が含まれていました。[ 90 ]
公式カンファレンスに加えて、Nim はさまざまな他のコンベンションでも取り上げられてきました。2015年のO'Reilly Open Source Convention (OSCON) では、Nim に関するプレゼンテーションが行われました。 [ 91 ] [ 92 ] [ 93 ] 2020 年のFOSDEMでは、言語の作成者である Andreas Rumpf を含む4 人のスピーカーが Nim を代表しました。 [ 94 ] 2022 年の FOSDEM では、 COVID-19 パンデミックのため、Nim は独自の開発者ルームを仮想的に開催しました。[ 95 ]並行処理、組み込みプログラミング、 GPU向けプログラミング、エンティティコンポーネントシステム、ゲーム開発、ルールエンジン、Python相互運用、メタプログラミングに関する講演が行われました。[ 96 ]
{{cite web}}: CS1 maint: 数値名: 著者リスト (リンク)