よくある質問と回答 (FAQ)

車輪の再発明 (YAPL) の必要性

プログラミング言語 Supernova では「I want window and the window title is hello world.」と入力すると “Hello, World!” のウィンドウタイトルで GUI ウィンドウを作成します。

つまり、自然言語コードにより「まるで英語のようにプログラミングで人間の言語能力をいかんなく発揮できる」ことを発見しましたが、実現には新しいプログラミング言語が必要です。

  1. 汎用性

  2. 実用性

  3. 非常に手軽な方法で自然言語プログラムの作成ができます。

これにより、使いやすく生産性を最大限まで押し上げることができるシステムを享受できます。

以上の目的を達成する最良の方法として Ring を開発しました。故に Ring は Yet Another Programming Language (YAPL) という車輪の再発明とは言い切れません。

さて、 Supernova はアイディアの検証であり、どのような利点と欠点があるかについての見識を得るために役に立ちました。 新しいアイディアの検証後に実用的なプログラミング言語があります。 Supernova の後に Ring があります。 ABC の後に Python が存在するのと同じ物語です。 Python は ABC の問題を回避していますが ABC の利点をもたらします。 Ring は Ruby と Ruby on Rails (ROR) の伝説を学んでいます。 プログラミング言語の実力は、汎用プログラミング言語で使われる優れたフレームワークに最も現れます。 また Ring には明確な目的と動機である「次世代版 Programming Without Coding Technology (PWCT) ソフトウェアの開発」があり、 C 言語で Unix オペレーティングシステムが設計されたことも学んでいます。 言い換えれば、各々の設計判断で決定する目標があります。

さて、質問です。計算機プログラミングの概念に関する知識を持たずに、非常に強力なソフトウェアを製作できますか? 科学的な答えは「ビジュアル・プログラミング」と「自然言語プログラミング」です。 実際には、ほかに問題をもたらすことなく、パラダイムを切り替えることはありません。

Ring (コンパイラ + 仮想計算機) の設計と開発、および C コードの生成では、 ビジュアル・プログラミング言語「Programming Without Coding Technology (PWCT)」を 100% 使用しています (一行たりとも手作業でのコーディングはしていません)。

Programming Without Coding Technology (PWCT) の利点は?

  1. 高速化。

  2. シンタックスエラーとは無縁となります。

  3. 高水準の抽象化となるためコードの理解と管理は容易になります。

  4. コードの記述はすべて管理できるため致命的な欠点はなくなります。

以上のアイディアへの対応、パラダイム切り替え時に発生する問題の解決、強力なビジュアル・プログラミングツールの開発のための言語設計 (Qt 対応などユーザインタフェースの作成機能を最重要視)、未来のコード不要プログラミング (自然言語の使用) 対応のための設計、実用的手法による自然言語プログラミングの実現、多種多様な方法での問題解決、および画期的な問題解決方法に関するアイディアの支援。

そして、C, C++, C#, Lua, PHP, Python, Ruby, Harbour, Basic と Supernova などのプログラミング言語の豊富な経験とビジュアル・プログラミング (使用経験十年以上)、および自然言語プログラミング (使用経験五年以上) の長期にわたる研究の集大成として、現役プログラマの認識へ変革をもたらし実用プログラミング言語の新天地と成るべく Ring を設計・開発しました。

プログラミング言語もそうですが、ソフトウェアの分野・用途を問わず、プログラマ、または開発者は意見や批評をする自由があります。 Ring も例外ではなく、ドキュメントの練度・整備不足による誤解、あるいはプログラマによく知られているがために背景にあるアイディアを見落してしまい、新規性がないと評価・判断を誤り、誤解されてしまう各種機能があります。

正しく評価するには、設計段階から実装段階へ移行後に、新たに自然言語インタフェースの実装を行い、 ソフトウェアを言葉で表現することにより Ring のプログラミングを始めてみてください (筆者としては、アイジャル・メソッドは任意であり、移行段階や移行時期についての決定は行いません)。

Ring は新興プログラミング言語であるため、選択肢は三つあります:

  1. 今は気にしません。

  2. Ring の将来について考え、プログラミング言語に関する考えを理解して応援したいのでしたら、ご支援をお願いします。

  3. ご期待に添えず申し訳ございません。また数年後の使用再開をお待ちしております。ご感想やご要望、バグレポートがございましたらお気軽にお寄せくださいませ。

まとめ

  • Programming Without Coding Technology (PWCT) 2.0 の完成後は Ring で高品質かつ大規模ソフトウェアを開発できるようになります。

  • 宣言型と自然言語パラダイムを段階的に押し進めていきます。

  • 次の公開版では、ネットワーク・プログラミングと平行性のために、新しいパラダイムの実装計画があります。去年、簡易試作品で新しいパラダイムを検証しました。なお、将来の公開版で Ring と統合する予定です。

Ring アーキテクチャとは?

アーキテクチャの構成は、

  1. Ring アプリケーション (自作コード) - Ring で記述 - ring/applications フォルダを参照してください。

  2. Ring ライブラリ (StdLib, WebLib, GameEngine, など) - Ring で記述 - ring/libraries フォルダを参照してください。

  3. Ring 拡張機能 (RingAllegro, RingQt, など) - C/C++ で記述 (Ring コードもあります) - ring/extensions フォルダを参照してください。

  4. Ring 仮想機械 (Ring VM) - C 言語で記述

  5. オペレーティングシステム (現在のプラットフォーム) - (Windows, Linux, macOS, Android, など)

拡張機能の実装方法は動的ライブラリです (DLL, So, Dylib)。 拡張機能の更新時、自作コードの更新は不要です。

フォルダ (ring/extensions/libdepwin) ====> Windows プラットホーム用の Ring 拡張機能 (C 言語で記述) をビルドするために使用される C ライブラリ

フォルダ (ring/libraries) ====> Ring で記述した Ring ライブラリ (StdLib, WebLib, GameEngine など)

フォルダ (ring/language/visualsrc) ====> Ring コンパイラと Ring VM のビジュアル版ソースコードは Programming Without Coding Technology (PWCT) で開発

フォルダ (ring/language/visualsrc) ====> Ring コンパイラと Ring VM のビジュアル版ソースコードは Programming Without Coding Technology (PWCT) で開発

用語「Ring ライブラリ」の語釈は → Ring で記述したライブラリのコード

用語「Ring 拡張機能 」の語釈は → C または C++ で記述したライブラリのコード

Ring のメモリ管理方法は?

  1. 関数を呼び出し時、この関数で新しいスコープの取得を行い、このスコープ内へ変数を格納します。

この関数で一時作業用メモリを取得します。 この一時作業用メモリ内へ一時作業用リストを格納します。

これは関数呼び出し終了直後に全て削除されます (スコープの終了)。

  1. Ring でメモリを削除するには、

2.1 関数スコープの終了まで待機

2.2 代入演算子の使用

2.3 callgc() 関数の使用 (一時作業用メモリの削除、リストのみ)

  1. Ring のガベージコレクターではエスケープ解析と参照カウントを使用

90% の場合では、ガベージコレクターの実行を不要にするために エスケープ解析 が使用されます。 メモリから削除、および残存対象を即時認識します。

10% 以下の場合では Ring は参照カウントを使います。

例えば、関数へリストと部分リストを渡すとき、 Ring はリストを参照渡しで渡しますが、親リストを削除してしまうとどうなりますか?

この場合、部分リストは参照カウントを使います。そして親リストの削除時は関数の終了までメモリに残存します。

Ring では、参照、および代入演算子で値によるリストのコピーの回避を奨励していることを覚えておいてください。 そして、 Ring で参照カウントを使うときは非常に限定された特別な場合です。ほとんどの場合はエスケープ解析で十分であり、非常に高速であることです。

Ring 1.9 から参照カウントへの対応を Ring 拡張機能と低水準 C ポインタまで拡大しました。 例えば、 fopen() の使用時に fclose() の使用に関して注意深くなる必要はありません。また RingODBC, RingSQLite, RingMySQL, RingQt などの拡張機能でも同じことが言えます。

使用完了後、割り当てられた全資源はガーベジコレクターにより整理されます (最後の参照を失ったとき)。

Ring データ表現方法は?

  1. Ring において、文字列は「バイトから構成される配列」です。

Ring は 8 ビットクリーン実装であり、文字列内の各文字列は 8 ビット(1 バイト) です。

「Int2Bytes(), Float2Bytes() および Double2Bytes()」関数は文字列を返します。

文字列にはバイナリデータも格納できます。

mystring = read("myfile.exe")
  1. 変数について考えるときは、このことを覚えておいてください

  • 値 ---> 内容物 (データとしてメモリに格納するもの) - 低水準概念

  • 型 ---> どう内容物を扱うことができるか、あるいは取り扱い方法 (単なる論理的概念)

電子計算機のメモリ ----> [Bytes] (バイト) で格納 - 各バイトは 8 ビット - (ここでは単語「メモリ」の概念については扱いません)

メモリとプロセッサのレジスタ間で移動処理が行われるとき、これらのバイトは一緒にされてからまとめられます。 ここでは、例えば 32 ビットと 64 ビットの「レジスタの大きさ」は同じです。 また、バイトオーダーもあります。

プログラミング言語 ----> これらのバイトに型を追加 (単なる概念) することで取り扱いかたと処理方法について決定します。

さらに、プログラミング言語では「型変換」ができます —> ほとんどの場合、型は論理的概念であるため、実際は単なるデータです (バイト、バイトカウント、バイトオーダーなど)。

Ring 文字列 ----> これらのバイト (各バイトは 8 ビット) があるので、 Ring は文字列の大きさを認識します (数値として String構造体へ格納)。

よって NULL 文字の確認をしたり、あるい文字列の終端へ NULL 文字を追加しません (不要です)。

Ring VM 内部の処理全般では Ring データの大きさの確認を行い文字列をバイナリデータとして扱います (各文字は 8 ビット)。

C 言語では ---> 通常は各文字列の終端へ NULL 文字 (\0) を追加します。

また、文字列関数は NULL 文字を確認するため、バイナリデータを処理するには不適切です。

符号付き (Signed) vs 符号なし (Unsigned) ---> データの算術演算をするときに重要な論理的概念でありますが、データを格納するとき、格納されるデータが全て8 ビットの場合は一切考慮されません。 ---> よって注意する必要はありません。

Ring では、これらの詳細について考えないでください。この件に関しては利用者側から見えないようになっています。このおかげでアプリケーションとしたいことのために開発に集中できます。

C 言語で低水準コードの記述を行い、万物を支配したいならば (必要に応じて) C 言語を検討してください。 ----> 優れた処理能力とメモリ管理

うんざりするような細かいことを考えず開発に専念して Ring コードを記述したいならぱ Ring を検討してください。 -----> 優れた生産性と迅速なソフトウェアの開発完了

吉報「プロジェクトで Ring と C を併用できます」

  1. Int2Bytes(), Float2Bytes() および Double2Bytes() 関数

これらの関数の入力値は数値を扱います。---> 数値型 (int|float|double) に基づきバイト集合を変換します。 ---> 結果として、これらのバイトがある Ring 文字列を返します。

Int2Bytes() ---> Ring 文字列 (バイト集合) と文字列の大きさ = sizeof(int)

Float2Bytes() ---> Ring 文字列 (バイト集合) と文字列の大きさ = sizeof(float)

Double2Bytes() ---> Ring 文字列 (バイト集合) と文字列の大きさ = sizeof(double)

用例:

? len( int2bytes(1) )
? len( float2bytes(1) )
? len( double2bytes(1) )

実行結果:

4
4
8
  1. 数値の格納

数値使用時、 Ring はメモリの数値表現で Double データ型を常時使います。 数値への算術演算時、これを理解していることは重要です。

"" + 数値で数値を文字列へ変換するとき、あるいは文字列 (数値) で文字列を取得すると数値ごとの 1 バイト表現となります (記憶領域では好ましくはない考えかたですが、文字列処理で便利です)。

記憶領域の特定容量 (int|float|double) で数値表現をする必要があるならば、データをバイナリファイルとして書き出すときに bytes2int(), bytes2float() および bytes2double() を使用してください。

Ring 数値 (double) ----> int2bytes() - 数値を double から int へキャストしてバイトを返します ----> 4 バイト (Ring 文字列)

Ring 数値 (double) ----> float2bytes() - 数値を double から float へキャストしてバイトを返します ----> 4 バイト (Ring 文字列)

Ring 数値 (double) ----> double2bytes() - 数値 (double) でバイトを返します ----> 8 バイト (Ring 文字列)

Ring の内部処理に限り int 型が使用されますが、 Ring アプリケーション、またはコードでは数値型 (double) のみ使います。

  1. Unsigned() 関数

unsigned() 関数の第一と第二仮引数は数値を要求します。

unsigned(nNumber1,nNumber2,cOperator)

bytes2int() 関数はバイトを数値へ変換できます。

用例:

B = list(4)

for k=1 to 4
{
        B[k]= Space(4)
        for kk=1 to 4 { B[k][kk]= char(60+4*k +kk) }
        ? " B" +k +": " +B[k]
}

A12= Space(4)     A12= bytes2int(B[1]) ^ bytes2int(B[2])
? "A12: " +string(A12)
A34= Space(4)     A34= bytes2int(B[3]) ^ bytes2int(B[4])
? "A34: " +string(A34)
A12= space(4)     A12= Unsigned(bytes2int(B[1]),bytes2int(B[2]),"^")
? "unsigned A12: " +A12
A34= space(4)     A34= Unsigned(bytes2int(B[3]),bytes2int(B[4]),"^")
? "unsigned A34: " +A34

実行結果:

B1: ABCD
B2: EFGH
B3: IJKL
B4: MNOP
A12: 201589764
A34: 470025220
unsigned A12: 201589764
unsigned A34: 470025220

なぜ弱い型付けを採用したのですか?

これは最初の目標で重要なことです。 高速化と違和感の排除になるからです。 最初の規則: 最初のデータ型は最後の結果に影響します。 例えば "Print : " + 5 を入力すると、最初に文字列の 5 が表示された後に 5 は文字列へ変換されます。 そして 5 + "10" と入力すると最初に数値の "10" が表示された後に "10" は 10 へ変換されます。 これは同じ演算子を使用して数値と文字列との間で、すばやく変換するのに大いに役に立ちます。 変換を防ぎたい場合は (変換を防ぐコードを記述します)、コードの記述量がより少ない (さらに削除可能) ことに気付くと思います。

弱い型付け = 自動変換と 自動処理優れたもの であり、 正しく使用されている場合は 手動処理 より優れています。

Lisp や Smalltalk よりも Ring を選ぶ利点は?

Smalltalk と Lisp は、すばらしいプログラミング言語あり、背景にある様々な概念を気に入っています。 しかし、問題に基づいて適切なプログラミング言語を選択した後であれば、問題を定義できると確信しています。 筆者には解決したい問題があり、この問題において、前述のすばらしいプログラミング言語は理想的ではなかったので Ring を設計しました。

新しいプログラミング言語を設計するとき、過去から学べますが、 将来を見据えて未来へ向かって進まなくてダメなのです。おそらく、 読者は自然言語プログラミングの知識に関して、古典的知識に基づいていることは筆者も同意しますが、 別技法の実践により、これを実務に取り入れることができることを確認しています。 自然言語に関して読者が誤解していることは 文脈依存 です。 つまり、アイディアの表現方法に関して色々と考えることで使用できるようになります。

用例 : I want window contains 3 buttons.

一文で四つのオブジェクト (ウィンドウと三つのボタン) の作成を行い、ウィンドウへボタンを追加しました。 このような様々な物事を取り入れるのが、自然言語プログラミングの考えかたです。

ネイティブ C や C++ よりも Ring を選ぶ利点は?

Ring 言語では、多種多様なプログラミングパラダイムをまとめて扱うことができます。

  1. 言語構成要素では、類似の概念に関して類似のシンタックスを使用するため、あるプログラミングパラダイムから別のプログラミングパラダイムへの移行は容易です。

  2. パラダイムには相互作用性があり、ソフトウェアでは異なる階層で併用されます。

    例えば、ゲームエンジンの作成はオブジェクト指向プログラミングで、 ゲームのコードは宣言型プログラミング、または自然言語プログラミングで記述を行い、 シーンの背後では宣言型、または自然言語のコードはオブジェクト指向クラスを使えます。

  3. Ring は C/C++ よりも生産性が高く、違和感がありません。

  4. Ring は、動的プログラミング言語です。実行中にコードの生成と実行ができます。 Ring は動的型付け言語であり、柔軟性のために弱い型付けを採用しています。

  5. ガベージコレクターは、世代間 (エスケープ解析) および参照カウント方式で実装しています。非常に高速であり、さらにプログラマへ制御権を委任することで、いつでもメモリからデータを削除できます。

  6. C/C++ ライブラリが使えます。 Ring には C 関数、または C++ クラスからのラッパー作成用に、コード生成器が付属しています。さらなる処理能力を求めている。あるいは追加の外部ライブラリを使いたいときでも、簡単に実装できます。

Ring と Python との違いは? Ring はオープンソースなの?

もちろん。 Ring はオープンソースです (MIT ライセンス)。

全般的に筆者は Python と Ruby が好きですが、筆者には目的となる単純明快な変更があります。

  1. 英数大小文字の区別はしません。

  2. リストのインデックスは 1 から開始します。

  3. 関数の定義前に呼び出せます。

  4. Python 風のシンタックスを使用しない (インデント、self の使用、pass & _)

  5. 弱い型付け (コンテキストに基づいた型の間での自動変換)

  6. プログラムは、単純明快な一定の構造に従います (ステートメントの後に関数、続いてパッケージとクラス)。

  7. 代入と値のテストで ‘=’ 演算子の使用。

重要な変更は、

  1. 数日で習得できる単純明快な小規模プログラミング言語: Ring コンパイラ + 仮想計算機 = 約 20,000 行の ANSI C コード (すべてのプラットフォームでコンパイル可能)。ほかにライブラリ関連と C/C++ プログラム用のオプションで 500,000 行。

  2. ガベージコレクター: エスケープ解析・参照カウント方式の採用、および代入演算子によりメモリの削除を行う機会をプログラマが決定する権限を与えています。

  3. 簡潔なシンタックス: Ring では、行は重要ではありません。 ; の記述または ENTER を押してステートメントを区切る必要はありません。

  4. オブジェクトの属性とメソッドの使用後は { } でオブジェクトへアクセスできます。

  5. 自然言語プログラミング: オブジェクト指向プログラミングにより違和感のない自然なインタフェースの作成が非常に簡単になります。

  6. 多重構造の宣言型プログラミング

さらに、 Ring の目的を達成するために、画期的な機能が追加されています (参照: 言語設計 - 明確な設計目標)。

Perl, PHP, Python や Ruby よりも Ring を使用する利点は?

  1. Ring は多機能で違和感がない上に、画期的で新規性があります。コードも美しく、簡潔で分かりやすく記述できます。 Ring はプログラミングに関する様々なことを考えさせられます。

  2. Ring は小規模言語として設計されています (Lua 言語からの教訓)。

  3. Ring は単純明快です (BASIC と Clipper/Harbour 言語からの教訓)。

  4. Ring はより自然言語的です (Supernova 言語からの教訓)。

  5. Ring はより宣言的です (REBOL と QML 言語からの教訓)。

  6. Ring の実装は透過性があり、視覚的であり、さらに豪華な機能があります。

なお、 Ring は PHP, Lua Tcl や Smalltalk などの改良品や代用品として設計しておりません。

C# や Java よりも Ring を使用する利点は?

  1. 簡潔なコード (きれいで違和感がない)、生産性と柔軟性の向上。

  2. 宣言型プログラミング、および自然言語プログラミングに関する対応の改善。

関数型プログラミングへの対応が言及されていますが、これは他になにが起きますか?

このコードに関する質問です:

f = func {
    a = 42
    return func { return a }
}

innerF = call f()
call innerF()

実行結果:

Using uninitialized variable : a In function _ring_anonymous_func_16601()

回答:

  • これは無名関数であり、クロージャー (関数閉包) ではありません。

  • この世界の開発者たちがクロージャーの実装を要望しましたが、 Ring 言語の開発で新しい機能を追加することは Ring 言語の目的と精神に反することです。

  • 関数とステートを統合したいときはクラスとオブジェクトを使うのが明確な解決方法です。

  • リストを使用してリストの内側に無名関数を記述すると、ステートと関数のあるリストを返せます。なお、使用時は関数へリストを渡します。

  • eval() および substr() を使うと、無名関数を返す前に変数の値を追加できます。

  • 関数の定義時に、ほかのスコープを保護します。Ring では最大で三種類のスコープに属する各場所で、三種類のスコープ規則があります (グローバル、オブジェクトのスコープ、およびローカルスコープ)。

  • ほかのプログラミング言語を、全て真似をする必要もありませんし、真似しても全て得られるわけではありません! そのように考えているならば、非常に複雑怪奇なプログラミング言語を作成するか、時間を節約するために他のプログラミング言語を使うと思います。

  • 新しいプログラミング言語の学習、または勉強に専念して (Ring の新しいところや優れたところ)、 いつから使い始めるかについて考えることがあります。数ヶ月前に、公開されたプログラミング言語と数年前に開発が始まったプログラミング言語を比較すること、および現在の世界で使用されているプログラミング言語をすべて理解したと錯覚しないでください。

  • 各々のプログラミング言語にある理解できないことが、ほかのプログラミング言語では特徴となります。アイディアは機能でありません。すべての機能に隠された精神と才能です。

シンタックスの処理ではなく自作言語の定義機能があり、コードなどで構文解析の使用を可能にしている理由は?

つまり、画期的です - 構文解析関連の学習をせずに、自然言語ステートメントを作成できます。 聡明な判断により、クラスを使います (後でコンテキストに基づき 様々なステートメントへ対応するクラスを併用できるようにするためです - ステートメントの変更と変換など様々なことができます)。 また、すべての Ring ステートメントを Ring 環境から使えるようにするステートメントを追加してあります。

ループの中断時に数値の指定ができる理由は?

Ring は小規模プログラミングと大規模プログラミングに対応しています。 目的と手段に基づいて使用する機能を選択します。 お望みとあれば、プログラマはプログラミング言語で粗悪なコードを記述できます。 このアイディアは、柔軟性破壊などの問題を起こさせないために、言語設計でエラー対策を盛り込む必要があります。

例えば、 Linux カーネルと Ruby の実装としてコードのある箇所を読むと、普段は使用しない一般的規則による実用的な GOTO の用法と用例を理解するでしょう。また、優れたプログラマは、いつ規則を破るべきか知っています。 Ring において GOTO は使用不能であり、実装予定については一切言及しません。 しかし、一階層以上のループを中断する機能や下位関数からループを中断する機能は、小規模プログラムでは実用的です。

とにかく、これらは言語により追加された小さな新機能の一部です (重要なアイディアではありません)。

Ring で ‘See’, ‘Give’, ‘But’ および ‘Ok’ キーワードを採用する理由は?

See と Give は “反対の動作” ではありませんが、プログラマがしたいことをするために選びました。

画面から処理の過程や結果を確認したいときは ‘See’ です。

キーボードからの標準入力をプログラムへ与えたいときは ‘Give’ です。

“but” や “ok” を選んだ根拠は簡単に書けるキーワードだからです。

また elseif/elif/elsif は文脈ごとに違うキーワードを使い分ける必要があるため "but" のほうが覚えやすいです。

これらは Ring 1.1 以降ではオプション扱いです。

‘See’ と ‘Give’ の代わりに ‘Put’ と ‘Get’ を使えます。

‘But’ と‘Ok’ の代わりに‘elseif’ または ‘end’ を使えます。

それは読者の選択にゆだねられています。 Ring には複数の記法とシンタックスの柔軟性があります。

また、自然言語の新規定義、および言語のキーワードと演算子を変更可能です。

Ring においてデータ型の背景にある哲学とは?

Ring は開発で求められる基本概念を実装しています! 可能な限り、基本概念は単純明快・小規模を維持するのが目標の一つです。

Ring におけるリストの用法で可能なこと

  • 配列の作成 (単体データ型)

  • リストの作成 (混成データ型)

  • ツリーの作成 (多重配列)

  • インデックスに文字列を使用 (ディクショナリー・ハッシュテーブル風の記法)

同じ原則は、これらを数値に使うときにも適用されます。

  • int 値

  • double 値

  • Boolean 値 (True/False)

この事例の原則は、下記を文字列へ格納するときにも適用されます。

  • 文字

  • テキスト (一行以上)

  • バイナリデータ

  • 日付

  • 日時

  • NULL 値 (空の文字列)

プログラマが新しいデータ型を定義することで、言語の定義済みデフォルト型として 使用できるオブジェクト指向への対応。つまり、 + 演算子のオーバーロードがあります。

よって、このようになりました。

  • 高速化のため、 Ring 言語では基本型 (文字列、数値、リスト、オブジェクト) が扱えます。

  • オブジェクト指向プログラミングを採用しています。アプリケーションの問題領域に従い、新しい型を追加することで拡張できる柔軟なプログラミング言語です。

Ring でのブール値とは?

コードでブール式の結果を判定するときに

true (真) では 1 を、および false (偽) では 0 を使えます。

see 命令で値を表示するときに 1 は (true) であり、 0 は (false) を表示します。

理由は?

Ring には四種類の型があるからです。

  1. 数値

  2. 文字列

  3. リスト

  4. オブジェクト

最初の型 (数値) は、 int (整数)、倍精度数、ブール値を表すために使用されます。

二番目の型 (文字列) は、 char (文字) 型、文字の配列、日付と時刻を表すために使用されます。

三番目の型 (リスト) は配列型であり、複合型から構成される配列として、ハッシュ (ディクショナリ)、ツリーなどを表すために使用されます。

オブジェクトは、 Ring のクラス (全てのクラス) または C/C++ 関数、メソッドを呼び出すことで得られる C ポインタから作成されたオブジェクトです。

なぜですか?

Ring はプログラマ、開発者が様々な作業で使えるように 最も単純明快な概念で設計されています。問題領域の定義に関心があるならば、 プログラマ、開発者は様々な型を取得するために、新しいクラス (および演算子のオーバーロード)を作成することで言語をカスタマイズします。

どうしてですか?

単純明快であることは習得と記憶しやすいため優れています! さらに、これは基本型で表現可能な高水準型の間における変換の柔軟性があります。

Ring に “Main” 関数を実装した理由は?

Main 関数は非常に重要です。グローバルスコープではなく、 ローカル変数を使うステートメントを書きたいときに使えます。

用例:

x = 10
myfunc()
See "X value = " + X  # ここでは x の値は (10) と想定します。
                      # しかし myfunc() で x を使用しているため別の値 (6) になります!
Func myfunc
   for x = 1 to 5
       See x + nl
   next

実行結果:

1
2
3
4
5
X value = 6

Main 関数の使用

Func Main
   x = 10
   myfunc()
   See "X value = " + X

Func myfunc
   for x = 1 to 5
       See x + nl
   next

実行結果:

1
2
3
4
5
X value = 10

Ring のインデックスが 1 から始まる理由は?

実生活では、三個のリンゴを手に持って数えるとき、

1 2 3 と数えます。

0 から数えることはしません。

質問: ほかのプログラミング言語において、インデックスが必ず 0 から開始されるのか?

回答: これは、計算機における値とメモリアドレスの取り扱い方法について関係があります。

用例:

myarray[5] 配列があります。

メモリには: myarray のアドレスがあります。

最初の項目は、アドレスへ格納されます。

二番目の項目は、アドレスの後などにあります。

myarray のアドレスで必要となる最初のアドレスを指し示す必要がある場合は

myarray + 0 の結果は、最初にある項目を指し示すため、そのまま myarray[0] と入力します。

myarray + 1 の結果は、二番目などにある項目を指し示すため、 myarray[1] と入力します。

このような仕組みは、低水準言語またはハードウェア寄りの言語では良いことです。

しかし、アプリケーション開発用に設計された高級言語では、違和感のない仕組みのほうが優れています。

用例:

mylist = [1,2,3,4,5]
for x = 1 to len(mylist)
        see x + nl
next

前述の用例では、配列の長さは 1 から開始します。 0 から開始するインデックスを記述する場合は、

for x = 0 to len(mylist)-1

また、 ほかのプログラミング言語の for ループのようにする方法を覚えておいてください。

for(x=0 ; x<nMax ; x++ )

< 演算子を使用してください! (ZeroLib も使えます)

英数大小文字を区別しない理由は?

  1. もっとひとにやさしくするため。

  2. Ada, SQL, Pascal, Delphi, Visual Basic, Visual FoxPro に影響を受けたため。

  3. 自然言語プログラミングの対応において効果的であるため。

  4. プログラミング言語のキーワードを記述するとき、好みの記法を選択できるようにするため。

see "lower case!"
SEE "UPPER case!"
See "First Letter is UPPER case!"
  1. 手軽なテストを書くために、 “Variable” ではなく “variable” を入力してしまった後にエラーメッセージになるのを防ぐため。

  2. “dosomething()” ではなく、 “Dosomething()” を入力してしまった後にエラーメッセージになるのを防ぐため。

  3. Ring では、変数、メソッド名、およびクラス名の間で名前衝突を起こさないため。

変数名として、 person および クラス名として Person を記述できます。

person = new Person
class Person
        name address phone

大小英数を区別したい場合は、キーワードと演算子の再定義 (またはプリプロセッサを自作)、あるいは全角英数を使用してください。

代入演算子で深いコピーを使用する理由は?

“つまり、実行性能の利得に関しては疑問と劣悪な等価交換があります。

第三者による証明が行われるまで、深いコピー vs 浅いコピーの良い手引きとしては深いコピーのほうが好ましいです。” ― スティーブ・マコーネル、コンプリートコードより

  1. 代入演算子では深いコピーを要求したほうが違和感がありません。

  2. 深いコピーが不要ならば、使用しないだけで良いです!

  3. Ring は、できる限り参照の使用を減らすように設計しています。

  4. Ring は、これが意味がある特別な場合において、参照を単純かつ可能にするために設計されています。

  5. 関数へのリスト、およびオブジェクト渡すとき、 C/C++ ライブラリからオブジェクトを

    作成時 (GUI オブジェクトなど)、リストの内側に格納されている オブジェクトを返すときなど、これが当然である場合は参照となります。

  6. これは機能であり、純粋関数を作成するために使えます。これが必要なとき、

    stdlib の Value() 関数は、この機能で値によるリストとオブジェクトを渡します。

  7. 参照が必要なときは、リストを共有管理するためのクラスとオブジェクトの作成を推奨します。

  8. 様々なロジックエラーを回避することは、アプリケーションの水準ではより安全なことです。

  9. Ring では、つまらない、細かいことに関して考えずに開発を開始してアプリケーションに専念するため、型を記述しなくても良いです (動的型付け)。

    また、数値、および文字列の間で明示的変換を記述しなくても良いです (弱い型付け)。 さらに、値または参照、および使用の間で選択しなくても良いです。 そして、スコープを記述しなくても良いです (レキシカルスコープ)。

  10. Ring には、スマートガベージコレクター (単純で高速) があります。代入演算子を使用すれば、いつでも好きなときにメモリを削除できます。

    これは参照の削減方法、または管理プログラムから使うことは、当目的を達成するのに大いに有効です。 これによる完全な制御があります。

  11. 参照の作成、および管理の作成を回避したい場合は

    Object2Pointer() と Pointer2Object() 関数を使います。 しかし、これは Ring の “精神” に反しています。

Ring にコンストラクタメソッドはありますか?

例えば新しいオブジェクトの作成時、

new point

1 - Ring で認識されていないときは Ring は新しいオブジェクトの属性で用いる動的メモリ空間を割り当てます。

2 - Ring は手順①で作成されたオブジェクトのステートで現在のオブジェクトのスコープとローカルスコープを変更します。

3 - Ring は実行中に、クラスの範囲を移動します (クラス名の末尾、そしてメソッドの先頭)。

4 - クラスの範囲内にあるすべての命令やコードは、 Ring のコードとして実行されます。

5 - クラスの範囲が終端に到達、または Return 命令を使うと、制御はクラスの範囲から (新しい場所) へ移動します。

オブジェクトが追加された全属性は動的属性であるため、これは実行時に追加する属性を制御できます。

用例:

$3D = False
see  new point
$3D = True
see new point

class point
        x y
        if not $3D return ok
        z

実行結果:

x: NULL
y: NULL
x: NULL
y: NULL
z: NULL

新しいオブジェクトの作成時、 init() メソッドを呼び出すオプションがあります。

このメソッドはオブジェクトの作成後に、クラスの範囲にあるコードの実行すると呼び出されるため、オブジェクト属性で処理を行うことができます。

p1 = new point3d(100,200,300)
see p1

class point3d
        x y z
        func init p1,p2,p3
                x=p1 y=p2 z=p3

オブジェクトの新規作成時に起きていることは?

1 - オブジェクトの作成時に、クラスの範囲にあるコードは実行されます。そして、この範囲にあるコードに基づいたオブジェクトの属性があります。

2 - Ring は、メソッドの呼び出しを開始するまでオブジェクトに関して気にしません。

3 - メソッドの呼び出し時に、 Ring はオブジェクトのクラスと親クラスの確認を行い (継承を使用しているならば)、同一クラスに所属する全てのオブジェクトから現在または今後使用するためにメソッドを収集します。

4 - メソッドは動的であり、各オブジェクトはクラスのメソッドから取得するため、オブジェクトの作成後に、メソッドの追加、オブジェクトまたは作成されたオブジェクトの使用、または同一クラスから作成できます。

用例:

o1 = new point {x=10 y=20 z=30}
o2 = new point {x=100 y=200 z =300}

addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )

o1.print()
o2.print()

class point x y z

実行結果:

10
20
30
100
200
300

Getter と Setter メソッドでのアクセスにより属性を使えますか?

もちろんです。クラスの外側から属性の使用を開始するときに、 Setter/Getter メソッドは自動的に呼び出されます。 また、属性を使わずにメソッドを呼び出せます。読者の選択しだいです。

用例:

o1 = new Developer
o1.name = "Mahmoud"  see o1.name + nl
o1 { name = "Gal"  see name }
o1 { name = "Bert"  see name }

o1.setname("Marino")
see o1.getname()

Class Developer

                name language = "Ring Programming Language"

                func setname value
                                see "Message from SetName() Function!" + nl
                                name = value + " - " + language

                func getname
                                see "Message from GetName() Function!" + nl + nl
                                return "Mr. " + name + nl

実行結果:

Message from SetName() Function!
Message from GetName() Function!

Mr. Mahmoud - Ring Programming Language

Message from SetName() Function!
Message from GetName() Function!

Mr. Gal - Ring Programming Language
Message from SetName() Function!
Message from GetName() Function!

Mr. Bert - Ring Programming Language
Message from SetName() Function!
Message from GetName() Function!

Mr. Marino - Ring Programming Language

クラスを定義している間にグローバルな名前の検索を行う理由は?

質問は、なぜクラス属性の定義時に グローバル変数との名前衝突を回避しないのですか?

先頭にオプションの $ 記号で、グローバル変数名の問題解決になることを覚えておいてください。 Main 関数は、グローバル変数を避けるために効果があります。

回答:

Ring は動的プログラミング言語です。

実行時に、クラスの属性を決定できます (追加・削除)。

クラスの属性を定義している間は、実行 (指定のコード) できます。

用例①

oPerson = new Person
Class Person
   See "Welcome to the Ring language"

用例②

グローバル変数に基づき、属性をカスタマイズします。

$debug = true
oPerson = new Person
see oPerson
Class Person
    if $debug  date=date()  time=time() ok

前述の用例では、 $debug フラグに true が設定されているとき、 オブジェクトのステートへ Date と Time 属性を追加します。

用例③

グローバル変数に基づき、オブジェクトのインデックスを格納します。

$ObjectsCount = 0
oPerson = new Person
see oPerson
oPerson2 = new Person
see oPerson2
Class Person
      $ObjectsCount++
      nIndex = $ObjectsCount

実行結果:

nindex: 1.000000
nindex: 2.000000

一般的な用例:

  • データベースの接続後に、デーブルのカラムを取得します (グローバル変数やオブジェクトを使用)。

  • カラム名に基づき、クラスの属性を作成します。

  • 後でデータベースを修正します - 不要ならば、コードを修正しないでください。

柔軟性はありますが、すばらしい応答性による強力さがあることを覚えておいてください。

Ring でグローバル変数とクラスの属性名間の名前衝突を回避しない理由は?

このような場合の対応策です。

1 - $ などの特殊記号を使用せずに、グローバル変数を定義するためです。

2 - クラスには、特別なシンタックスで定義された属性があります (クラスの後に属性名を記入します)。

3 - 属性は、コードの記述とグローバル変数の使用が許されているクラスの範囲で定義されます。

クラスの範囲内で、 Ring の変数検出方法の変更について提案を受け入れる場合は、この問題よりも更に重要な問題を多発する前に三つの機能のうち一つを破る必要があります。

Ring のコードをもっと綺麗なものにしておきたいし、 $ を使用する・しないときをプログラマに決定させたいため機能番号①の変更は好ましくありません。

この機能は気に入っており、プログラマに Self.属性 の入力を強制するのは好みではないので機能番号②の変更は好ましくありません。

ほとんどのアプリケーションでは、クラスの範囲内でのグローバル変数へのアクセスは非常に重要であるため機能番号③の変更は好ましくありません。

判断理由は?

筆者は、この特例を回避するかはプログラマが決めるために、この事例を記載することにしました。

1 - グローバル変数の使用を回避でき (最良)、 Main 関数 (オプション扱い) を使えます。

2 - プログラマは変数名の先頭に $ あるいは global_ または g_ などの記号を使えます。

3 - プログラマは属性を定義するために、クラス名末尾に Self.属性 を使えます。

一般に、小規模プログラムではグローバル変数と関数を使います。大規模プログラムではクラスとオブジェクトを使いますので、グローバル変数は数本だけに絞るか、または使わないでください。

ftell() と fseek() でファイルの大きさを取得するには?

この関数はファイルの読み込みを行わずに、ファイルの大きさを取得します!

func getFileSize fp
       C_FILESTART = 0
       C_FILEEND = 2
       fseek(fp,0,C_FILEEND)
       nFileSize = ftell(fp)
       fseek(fp,0,C_FILESTART)
       return nFileSize

注釈

前述の関数では仮引数として、 fp (ファイルポインタ) を扱います。 fopen() 関数で開いているファイルから fp を取得できます。

fp = fopen("filename","r")

see  "File Size : " + getFileSize(fp) + nl

別の解決方法 (ファイルの読み取り):

see len(read("filename"))

現在のソースファイルのパスを取得するには?

この関数で、現在のソースファイルのパスを取得します。 そして、パスを扱うための変数へファイル名を追加できます。

cPath = CurrentPath()
func currentpath
        cFileName = filename()
        for x = len(cFileName) to 1 step -1
                if cFileName[x] = "/"
                        return left(cFileName,x-1)
                ok
        next
        return cFileName

関数の定義済み仮引数、またはオプションの仮引数とは?

定義済み仮引数、またはオプションの仮引数を使用したい場合は、ハッシュ、ディクショナリなどのリストを受け入れてください。

用例:

sum([ :a = 1, :b = 2])
sum([ :a = 1 ])
sum([ :b = 2 ])
func sum pList
        if plist[:a] = NULL pList[:a] = 4 ok
        if plist[:b] = NULL pList[:b] = 5 ok
        see pList[:a] + pList[:b] + nl

実行結果:

3
6
6

リストやディクショナリでキーまたは値のみを表示するには?

キーまたは値のみを表示したい場合は、項目のインデックスを選択します (1 または 2)。

用例

C_COUNTRY = 1
C_CITY = 2
mylist = [
        :KSA = "Riyadh" ,
        :Egypt = "Cairo"
]

for x in mylist
        see x[C_COUNTRY] + nl
next

for x in mylist
        see x[C_CITY] + nl
next

実行結果:

ksa
egypt
Riyadh
Cairo

リストで nl を表示するときに変な結果になる理由は?

このコードでは、

list = 1:5        # list = [1,2,3,4,5]
see list + nl

リストへ改行を追加後にリストを表示します。つまり、通常のリスト表示では、リストの末尾にある改行も表示します。 新しい改行文字を追加したので、改行は二行表示となります。

See <>

see 命令は式の最終結果を表示するため、このように式が評価されます。

nl = char(13) + char(10) # 変更可能な変数!

+ は演算子です。

文字列 + 文字列 ---> 新しい文字列
文字列 + 数値   ---> 新しい文字列
数値   + 数値   ---> 新しい数値
数値   + 文字列 ---> 新しい数値

リスト + 項目 ---> なにも新規作成されませんが、同じリストへ項目が追加されます。

例外:

数値 + nl ---> 新しい文字列

この例外は数値の表示後に、改行を簡単にできるよう追加されています。

最後の項目を表示した後には、改行が既にあるため、これはリストを表示するためには不要です。

StrCmp() の実行結果について解説していただけますか?

まず、 ‘=’ 演算子でも文字列を検査できることを覚えておいてください。

see strcmp("hello","hello") + nl +
strcmp("abc","bcd") + nl +
strcmp("bcd","abc") + nl

いずれも、同一文字列ならば 0 を返します。

abc と bcd は違います。二行目は -1 を返しており三行目は 1 を返します。

二行目では “abc” と “bcd” の比較を行っています。

“abc” = “a” の一文字目と “bcd” = “b” の一文字は等しくありません。 よって “a” != “b” と “a” < “b” の結果となります。

よって “a” != “b” と “a” < “b” の

実行結果は -1 となります。

三行目には “bcd” と “abc” があります。

“bcd” の一文字目は “b” であり “abc” の一文字は= “a” です。

結果は “b” != “a” と “b” > “a” です。

従って、実行結果は 1 となります。

注釈

ASCII(“a”) は 97 であり ASCII(“b”) は 98 です。よって 97 < 98 であるため “a” は “b” 以下となります。詳しくは ASCII コード表をご確認ください。

プロジェクトで複数のソースコードを使うには?

用例:

このようなフォルダがあります。

C:\LRing

このようなファイルがフォルダにあります。

C:\LRing\t1.ring
C:\LRing\mylib.ring
C:\LRing\libs\mylib2.ring

このようなコードが t1.ring ファイルにあります。

load "mylib.ring"
load "libs\mylib2.ring"
myfunc()
test()

このようなコードが mylib.ring ファイルにあります。

func myfunc
        see "message from myfunc"+nl

このようなコードが libsmylib2.ring ファイルにあります。

func test
        see "message from test" + nl

C:\LRing フォルダから。

Ring のパスを追加していない場合は、このコマンドで追加できます。

set path=%path%;c:\ring\bin;

Ring フォルダ C:\Ring のある場所で

実行します。

Ring t1.ring

実行結果:

message from myfunc
message from test

この用例で GetChar() を二度使用する理由は?

GetChar() 関数は、キーボードバッファから一文字受け取ります。

この用例では、

While True
        See "
                Main Menu
                (1) Say Hello
                (2) Exit
        "
        Option = GetChar()
        GetChar() GetChar()  # 行の終わり
        # この行で前述の二行を置換できます。
        # Give Option

        if Option = 1
                see "Enter your name : " give cName
                see "Hello " + cName
        else
                bye
        ok
End

GetChar() を三回使用しています。

最初はユーザの選択肢を取得するときに、

Option = GetChar()

しかし、二回目と三回目があります (バッファから改行文字を受け取ります)。

GetChar() GetChar()  # 行の終わり

用例: ユーザが選択肢から 1 を選んだ後に ENTER を押します。

ここでは、三文字あります。

  • 一文字目は : 数字の 1 です。

  • 二文字目は : CHAR(13) です。

  • 三文字目は : CHAR(10) です。

Windows において、 CHAR(13) および CHAR(10) は、それぞれ改行となります (すなわち CR+LF)。

NULL と isNULL() 関数の用法は?

Ring では、未初期化変数を使うと、明示的なランタイムエラーメッセージが表示されます。

用例:

See x

実行結果:

Line 1 Error (R24) : Using uninitialized variable : x
in file tests\seeuninit.ring

未初期化の属性へアクセスすると、同じことが起こります。

用例:

o1 = new point
see o1
see o1.x
class point x y z

実行結果

x: NULL
y: NULL
z: NULL

Line 3 Error (R24) : Using uninitialized variable : x
in file tests\seeuninit2.ring

エラーを検査したい場合は、 Try/Catch/End を使用してください。

Try
        see x
Catch
        See "Sorry, We can't use x!" + nl
Done

実行結果:

Sorry, We can't use x!

さて、 NULL と isNULL() についてお話します。

未初期化の変数を扱おうとしたとき、エラーメッセージが出ます。

これらのエラーは Try/Catch/Done で検査できます。文字列で扱うためには NULL と isNULL() を使います。

NULL には、空文字列の変数があります。

isNULL() は関数であり、入力が空の文字列、または文字列の内容が “NULL” ならば true (1) を返します。

これらの値 (空の文字列) をテストする必要があり、 DBMS などの外部リソースから “NULL” を有する文字列が入力されることがあるからです。

用例:

See isNULL(5) + nl +        # 0 の表示
isNULL("hello") + nl +      # 0 の表示
isNULL([1,3,5]) + nl +      # 0 の表示
isNULL("") + nl +           # 1 の表示
isNULL("NULL")              # 1 の表示

オブジェクトのあるリストを表示するには?

この用例では、オブジェクトのあるリストの表示方法を確認します。

aList = [[1,2,3] , new point(1,2,3), new point(1,2,3)]
see "print the list" + nl
see alist
see "print the item (object)" + nl
see alist[2]
class point x y z
        func init p1,p2,p3 x=p1 y=p2 z=p3

実行結果:

print the list
1
2
3
x: 1.000000
y: 2.000000
z: 3.000000
x: 1.000000
y: 2.000000
z: 3.000000
print the item (object)
x: 1.000000
y: 2.000000
z: 3.000000

改行と文字を表示するには?

nl 変数で改行します。

See "Hello" + nl

複数行リテラルでも改行します。

See "Hello

"

char(nASCII) 関数で他の文字を表示します。

See char(109) + nl +    # m の表示
    char(77)            # M の表示

QApp クラス名の末尾に () を付けない理由は?

RingQt による GUI の開発では、新しいオブジェクトの作成時にクラス名の末尾に () を使います。例えば、

new qWidget() { setWindowTitle("Hello World") resize(400,400) show() }

この処理の前に、 qApp クラスからオブジェクトを作成しますが、名前の後ろには () を使いません。

Load "guilib.ring"
app = new qApp
{
    win=new qWidget()
    {
        setwindowtitle(:test)
        show()
    }
    exec()
}

クラス名末尾に () を使うと、クラス内にある init() メソッドの呼び出し、およびこのメソッドへの仮引数を渡す意味になります。

クラス内に init() がないメソッドで () を使うと、例外エラーメッセージになります。

そのほかのクラスには、 init() メソッドはありますが qApp クラスにはありません。 関数を使用したオブジェクトのポインタを返すオブジェクトの作成に必要であり、 このポインタは pObject 属性に格納されるのが理由です。 詳しくは ring_qt.ring ファイルに収録されているクラスを参照してください。

ウィンドウのタイトルバーが画面外に移動してしまう原因は?

このコードを記述した場合、

Load "guilib.ring"
app = new qApp
{
        win=new qWidget()
        {
              setwindowtitle(:test)
              setGeometry(0,0,200,200)
              show()
        }
        exec()
}

ウィンドウが (200,200) の寸法で (0,0) の地点へ移動すると思うでしょう。 実際は、ウィンドウのタイトルバーが画面外に移動してしまいます。

これは Qt フレームワークの挙動と関連があります。

このコードで問題を回避します。

load "guilib.ring"
new qApp {
        new qWidget() {
                move(0,0)
                resize(200,200)
                show()
        }
        exec()
}

GUI アプリケーションでボタンの配列を作成するには?

この用例をご確認ください:

Load "guilib.ring"

App1 = new qApp {

        win1 = new qWidget() {
                move(0,0)
                resize(500,500)
                new qPushButton(win1)
                {
                        settext("OK")
                        setclickevent("click()")
                }
                btn1 = new qPushButton(win1)
                {
                        setgeometry(100,100,100,30)
                        settext("Button1")
                }

                btn2 = new qPushButton(win1)
                {
                        setgeometry(200,100,100,30)
                        settext("Button2")
                }

                button = [btn1, btn2]
                show()
        }

        exec()

}

func click

        button[1] { settext ("Button3") }
        button[2] { settext ("Button4") }

ウィンドウを閉じた後に別のウィンドウを表示するには?

この用例は、ウィンドウを閉じる方法と別のウィンドウを表示する方法です。

Load "guilib.ring"

app=new qApp
{
        frmBefore=new Qwidget()
        {
                setWindowTitle("before!")
                resize(300,320)
                move(200,200)

                button=new qPushButton(frmBefore)
                {
                        setText("Close")
                        setClickEvent("frmBefore.close() frmMain.show()")
                }

                show()
        }

        frmMain=new Qwidget()
        {
                setWindowTitle("After!")
                resize(300,320)
                move(200,200)
        }

        exec()

}

モーダルウィンドウの作成方法は?

この用例は、モーダルウィンドウの作成方法です。

load "guilib.ring"
app=new qApp
{
        frmStart=new Qwidget()
        {
                setWindowTitle("The First Window")
                resize(300,320)
                move(200,200)

                button=new qPushButton(frmStart)
                {
                        setText("Show Modal Window")
                        resize(200,30)
                        setClickEvent("frmModal.show()")
                }

                new qPushButton(frmStart)
                {
                        setText("Close Window")
                        move(0,50)
                        resize(200,30)
                        setClickEvent("frmStart.Close()")
                }

                show()
        }

        frmModal =new Qwidget()
        {
                setWindowTitle("Modal Window")
                resize(300,320)
                move(200,200)
                setparent(frmStart)
                setwindowmodality(true)
                setwindowflags(Qt_Dialog)
        }

        exec()

}

関連資料:

最大化ボタンの無効化およびウィンドウのサイズを変更するには?

setWindowFlags() メソッドを使います。

Load "guilib.ring"
app1 = new qapp {
                win1 = new qwidget() {
                                setwindowtitle("First")
                                setgeometry(100,100,500,500)

                                new qpushbutton(win1) {
                                                setgeometry(100,100,100,30)
                                                settext("close")
                                                setclickevent("app1.quit()")
                                }

                                new qpushbutton(win1) {
                                                setgeometry(250,100,100,30)
                                                settext("Second")
                                                setclickevent("second()")
                                }

                                showmaximized()
                }
                exec()
}

func second
                win2 = new qwidget() {
                                setwindowtitle("Second")
                                setgeometry(100,100,500,500)
                                setwindowflags(Qt_dialog)
                                show()
                }

ODBC から SQLite を使うには?

Ring 1.1 以降では SQLite に標準対応しており ODBC は不要です。

また、 RingQt から SQLite へアクセスできます。

質問への回答

pODBC = odbc_init()
odbc_connect(pODBC,"DRIVER=SQLite3 ODBC Driver;Database=mydb.db;LongNames=0;"+
                   "Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;")
odbc_execute(pODBC,"create table 'tel' ('ID','NAME','PHONE');")
odbc_execute(pODBC,"insert into 'tel' values ('1','Mahmoud','123456');")
odbc_execute(pODBC,"insert into 'tel' values ('2','Ahmed','123456');")
odbc_execute(pODBC,"insert into 'tel' values ('3','Ibrahim','123456');")
odbc_execute(pODBC,"select * from tel") + nl
nMax = odbc_colcount(pODBC)
See "Columns Count : " + nMax + nl
while odbc_fetch(pODBC)
        See nl
        for x = 1 to nMax
                see odbc_getdata(pODBC,x)
                if x != nMax see " - " ok
        next
end
odbc_disconnect(pODBC)
odbc_close(pODBC)

実行結果:

Columns Count : 3

1 - Mahmoud - 123456
2 - Ahmed - 123456
3 - Ibrahim - 123456

このプログラムは、ファイルを作成します : mydb.db

注意 : ODBC ドライバを表示したとき、そこにある長いリストを確認できます。

SQLite3 ODBC Driver - UsageCount=1
SQLite ODBC Driver - UsageCount=1
SQLite ODBC (UTF-8) Driver - UsageCount=1

そして “SQLite3 ODBC Driver” を使用しています。

dBase/Harbour データベースへ接続できますか?

多種多様なデータベースを ODBC で接続できます。

xBase ファイル (*.DBF) へ接続するには、

See "Using DBF Files using ODBC" + nl
pODBC = odbc_init()
See "Connect to database" + nl
odbc_connect(pODBC,"Driver={Microsoft dBase Driver (*.dbf)};"+
                   "datasource=dBase Files;DriverID=277")
See "Select data" + nl
odbc_execute(pODBC,"select * from tel.dbf")
nMax = odbc_colcount(pODBC)
See "Columns Count : " + nMax + nl
while odbc_fetch(pODBC)
           See "Row data:" + nl
           for x = 1 to nMax
                           see odbc_getdata(pODBC,x) + " - "
           next
end
See "Close database..." + nl
odbc_disconnect(pODBC)
odbc_close(pODBC)

実行結果

Using DBF Files using ODBC
Connect to database
Select data
Columns Count : 3
Row data:
Ahmad - Egypt - 234567 - Row data:
Fady - Egypt - 345678 - Row data:
Shady - Egypt - 456789 - Row data:
Mahmoud - Egypt - 123456 - Close database...

また Visual FoxPro データベースにも接続できます (Visual FoxPro ドライバのインストールが必要です)。

See "ODBC test 6" + nl
pODBC = odbc_init()
See "Connect to database" + nl
odbc_connect(pODBC,"Driver={Microsoft Visual FoxPro Driver};"+
        "SourceType=DBC;SourceDB=C:\PWCT19\ssbuild\PWCTDATA\CH1\Data\mydata.dbc;")
See "Select data" + nl
see odbc_execute(pODBC,"select * from t38") + nl
nMax = odbc_colcount(pODBC)
See "Columns Count : " + nMax + nl
while odbc_fetch(pODBC)
        See "Row data:" + nl
        for x = 1 to nMax
                see odbc_getdata(pODBC,x) + " - "
        next
end
See "Close database..." + nl
odbc_disconnect(pODBC)
odbc_close(pODBC)

setClickEvent() でオブジェクトのメソッドを参照しない理由は?

setClickEvent(cCode) は、コードを記入した文字列を扱えます。 イベントの発生時にコードは実行されます。

Ring は 手続き型、オブジェクト指向、関数型など様々なプログラミングパラダイムに対応しています。

プログラミング言語の水準で様々なパラダイムに対応するときは、以下の選択肢のうち、どちらのパラダイムが使用されるのか検出することはできません。

  1. 各種プログラミングパラダイムで動作する一般的な解決方法があります。

  2. あるパラダイムのうちの一つと合致する各種解決方法があります。

setClickEvent() および、そのほかは (様々なプログラミングパラダイムで動作する一般的な解決方法) に所属しています。

クラスとオブジェクトの取り扱いに関する注意を一切しなくても、文字列のコードを渡すことで実行されます。

このコードは関数の呼び出し、メソッドの呼び出しと変数の値の設定などができました。

そのほかのプログラミング言語では、イベントでオブジェクト指向プログラミングとメソッドの呼び出しを強制します。また、現在のオブジェクトなどの仮引数を取得するために無名関数を使います。

現在、一般的な解決方法はあります。将来は特定のパラダイムと合致する 明確な解決方法を追加するかもしれません (オブジェクト指向、宣言型プログラミング、および自然言語プログラミング)。

定義エラーを起こさずに関数を呼び出せる理由は?

プログラムは次の順序に従います。

  1. ファイルの読み込み

  2. グローバル変数とステートメント

  3. 関数

  4. パッケージ、クラスとメソッド

どのような意味がありますか?

  1. **** 関数がない場合は、その後はクラスとなります。 ****

  2. **** 関数、メソッド、クラス、パッケージを終わらせるための命令は不要です。 ****

この用例を参照してください。

See "Hello"
test()
func test
    see "message from the test function!" + nl
class test

前述の用例では、 test() 関数があるため test() から呼び出せます。

この用例では、 test() がメソッドになります。

See "Hello"
test()    # ランタイムエラーメッセージ
class test
        func test # Test() はメソッドです (関数ではない)
                see "message from the test method!" + nl

メソッドの定義後に、関数を呼び出すとエラーになります。

前述のプログラムは必ずこの通りにしてください。

See "Hello"
new test { test() }   # メソッドの呼び出し
class test
        func test # Test() はメソッドです (関数ではない)
                see "message from the test method!" + nl

RingQt の拡張機能とクラスの追加方法は?

一般に C または C++ のコードで Ring を拡張します。

Ring のコードから C 関数の呼び出し、または C++ クラスとメソッドを使えます。

詳しくは「C/C++ による拡張機能の開発方法」を参照してください。

このコードの用例では Ring ライブラリ (*.lib) を使用して *.c ファイルを DLL ファイルへコンパイルします。

#include "ring.h"

RING_FUNC(ring_ringlib_dlfunc)
{
        printf("Message from dlfunc");
}

RING_API void ringlib_init(RingState *pRingState)
{
        ring_vm_funcregister("dlfunc",ring_ringlib_dlfunc);
}

Ring は、 LoadLib() 関数で DLL ファイルを読み込んだ後に Ring 関数から dlfunc() 関数が呼び出されます。その後に C 関数を呼び出します。

See "Dynamic DLL" + NL
LoadLib("ringlib.dll")
dlfunc()

実行結果:

Dynamic DLL
Message from dlfunc

取扱説明書を読むと、仮引数 (文字列、数値、リストとオブジェクト) などの取得方法について知ることができます。

また、関数から値 (任意型) を返す方法も知ることができます。

実体験ですが、 C ライブラリまたは C++ ライブラリへ対応作業をしているとき、

ほとんどの関数で、ほとんどのコードを共有していることを発見しました。

こちらのコード生成器を使うと Ring 用の C/C++ ライブラリのラッパーを手軽に生成でき、時間の節約になります。

https://github.com/ring-lang/ring/blob/master/extensions/codegen/parsec.ring

コード生成器は 1200 行以下の Ring プログラムです。

コード生成器で入力した設定ファイルには C/C++ ライブラリの情報があります。

関数プロトタイプ、クラスとメソッド、定数、列挙体、構造体とメンバなど。

そして、コード生成器で生成します。

  • C ライブラリに関する *.C ファイル (ライブラリ関数を使用可能)

  • C++ ライブラリに関する *.CPP ファイル (C++ クラスとメソッドを使用可能)

  • *.Ring ファイル (C++ のクラスを Ring のクラスとして使用可能)

  • *.RH ファイル (定数)

コード生成器の動作を理解するには、この Allegro ゲームプログラミング・ライブラリ用の拡張機能を参照してください。

https://github.com/ring-lang/ring/tree/master/extensions/ringallegro

ひとつ目の設定ファイルは、

https://github.com/ring-lang/ring/blob/master/extensions/ringallegro/allegro.cf

このファイルは Allegro の取扱説明書と Ring コード生成器の規則を用いて記述しました。

このバッチファイルでコード生成器を実行します。

https://github.com/ring-lang/ring/blob/master/extensions/ringallegro/gencode.bat

または、このスクリプトを使います。

https://github.com/ring-lang/ring/blob/master/extensions/ringallegro/gencode.sh

生成されたソースコードファイルを取得します。

https://github.com/ring-lang/ring/blob/master/extensions/ringallegro/ring_allegro.c

生成されたソースコードファイル (ring_allegro.c) は約 1,2000 行です。

ですが、設定ファイルは 1000 行以下です。

ライブラリをビルドするには (DLL ファイルの作成)

https://github.com/ring-lang/ring/blob/master/extensions/ringallegro/buildvc.bat

また、この拡張機能は LibSDL ライブラリに関して確認できます。

https://github.com/ring-lang/ring/tree/master/extensions/ringsdl

まとめとして、知っておく必要のある関連事項は

1 - 設定ファイルの記述

2 - コード生成器の使用

3 - ライブラリや拡張機能の作成

4 - Ring コードからライブラリや拡張機能を使用

さて Qt についての質問へ移りましょう。

RingQt は Ringの拡張機能です (ringqt.dll)。

Ring の改修や変更は不要です。

  1. RingQt の変更が必要です。

  2. または、別の Qt ベースの拡張機能により、 Ring の機能を拡張します (だだし、同じ Qt バージョンです)。

最初の選択肢に関しては RingQt を参照してください。

https://github.com/ring-lang/ring/tree/master/extensions/ringqt

設定ファイル

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/classes/qt.cf

ソースコードを生成するには

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/gencode.bat

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/gencode.sh

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/gencodeandroid.bat

DLL/so/Dylib ファイルをビルドするには

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/buildmingw32.bat

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/buildgcc.sh

https://github.com/ring-lang/ring/blob/master/extensions/ringqt/buildclang.sh

RingQt の学習をしてください。

利用できる選択肢について学んでください。

  1. Qt のクラスを接続します。

  2. 新しい自作クラスを接続するために新しいクラスを作成します。

第二の選択肢は (前述の二つの要点、またはそれ以前にある二つの要点)、

C++ コードによる新しいクラスを作成します。

そして、作成したクラスを RingQt へ統合、または特別な DLL を用意します (判断に応じて)。

一般的な動作ならば、 RingQt に記述してください (他の人の手助けになります)。

特別な動作ならば、別の拡張機能に記述してください (特定のアプリケーション)。

Combobox および QTableWidget のセルへ他の要素を追加するには?

このコードを参照してください。

Load "guilib.ring"
New qApp
{
        win1 = new qMainWindow() {
                setGeometry(100,100,1100,370)
                setwindowtitle("Using QTableWidget")

                Table1 = new qTableWidget(win1) {
                        setrowcount(10) setcolumncount(10)
                        setGeometry(0,0,800,400)
                        setselectionbehavior(QAbstractItemView_SelectRows)

                        for x = 1 to 10
                                for y = 1 to 10
                                        item1 = new qtablewidgetitem("R"+X+"C"+Y)
                                        setitem(x-1,y-1, item1)
                                next
                        next

                        cmb = new QComboBox(Table1) {
                                alist = ["one","two","three","four","five"]
                                for x in aList additem(x,0) next
                        }
                                setCellWidget(5, 5, cmb)
                }

                setcentralwidget(table1)
                show()
        }
        exec()
}

QTableWidget で選択されたセルの内容に処理を行うには?

このサンプルを参照してください。

Load "guilib.ring"

New qApp {
        win1 = new qMainWindow() {
                setGeometry(100,100,800,600)
                setwindowtitle("Using QTableWidget")
                Table1 = new qTableWidget(win1) {
                        setrowcount(10) setcolumncount(10)
                        setGeometry(10,10,400,400)
                        for x = 1 to 10
                                for y = 1 to 10
                                        item1 = new qtablewidgetitem("10")
                                        setitem(x-1,y-1,item1)
                                next
                        next
                }
                btn1 = new qPushButton(win1) {
                        setText("Increase")
                        setGeometry(510,10,100,30)
                        setClickEvent("pClick()")
                }
                show()
        }
        exec()
}

func pClick
        for nRow = 0 to Table1.rowcount() - 1
                for nCol = 0 to Table1.columncount() - 1
                        Table1.item(nRow,nCol)  {
                                if isSelected()
                                        setText( "" + ( 10 + text()) )
                                ok
                        }
                next
        next

三種類の標準コード記法について

一般的なもの、あるいはコミュニティでの推薦記法を教えてください。

  1. 、まずは、記法を選んでください。ただし、同じプロジェクトで異なる記法の併用、

    または最低でも、同じコンテキストを併用しないでください (実装、テスト、スクリプトなど)。

注釈

プロジェクトの開始時に規則の明示、およびその規則に従ってください。

  1. 自作記法の使用 (キーワードの変更により) - この考えはカスタマイズと自由のためのものです。

注釈

自然言語を使用する場合など、明確な理由がある場合に限り、新しい記法の作成とキーワードの変更を行うほうが良いです (日本語、アラビア語、フランス語など)。

  1. 第一形式は質問、チュートリアル、および小規模アプリケーション・プログラム (5,000行以下のコード) には最適です (筆者個人の意見です)。

    用例 : Ring 取扱説明書、 Ring のサンプル、およびアプリケーションの大部分

  2. 第三形式は大規模アプリケーション、および現役プログラマには最適です (筆者個人の意見です)。