言語の変更
言語の変更のセクションでは、各バージョンで Dynamo の言語に加えられた更新と修正の概要について説明します。これらの変更は、機能、パフォーマンス、および使用状況に影響を与える可能性があります。このガイドは、ユーザーがこれらの更新プログラムに適応するタイミングと理由を理解するのに役立ちます。
Dynamo 2.0 の言語の変更点
list@level 構文を「@-1」から「@L1」に変更
list@-1 の代わりに list@L1 を使用する list@level の新しい構文
動機: コード構文をプレビュー/UI に合わせました。ユーザー テストでは、この新しい構文でより理解しやすくなることがわかっています。
Dynamo のタイプに合わせて TS で Int タイプと Double タイプを実装
引数が基数でのみ異なるオーバーロードされた関数を許可しない
削除されたオーバーロードを使用する古いグラフは、上位のオーバーロードを既定で使用する必要があります。
動機: どの関数が実行されているのかが曖昧になることを防ぐ
複製ガイドによる配列のプロモートを無効化
命令型ブロック内の変数を命令型ブロック スコープに対してローカルにする
命令型コード ブロック内で定義された変数値は、それを参照する命令型ブロック内で変更が行われることによって変更されることはありません。
Code Block ノードで自動調整更新を無効にするため、変数を固定にする
すべての UI ノードを静的メソッドにコンパイルする
代入のない return 文をサポート
関数定義でも命令型コードでも「=」は不要です。
CBN の古いメソッド名の移行
ライブラリ ブラウザのユーザー インタフェースで読みやすく、配置しやすくするために、多数のノードの名前が変更されました。
ディクショナリのクリーンアップ時のリスト
既知の問題:
命令型ブロック内の名前空間の競合が原因で予期しない入力ポートが表示されます。詳細については、Github の問題を参照してください。これを回避するには、命令型ブロックの外側で関数を次のように定義します。
Dynamo 2.0 の言語変更の説明
Dynamo 2.0 リリースでは、言語に多くの改善が加えられました。その主な動機は、言語を単純化することでした。DesignScript をより理解しやすく使いやすいものにすることに重点が置かれており、エンドユーザーの理解度を向上させることを目的として、より強力で柔軟なものにしています。
2.0 での変更点を以下に説明します。
簡略化された List@Level 構文
ランクのみが異なるパラメータを持つオーバーロードされたメソッドを不正とする
すべての UI ノードを静的メソッドとしてコンパイルする
複製ガイド/レーシング使用時のリストのプロモートを無効化
自動調整ブロック内の変数は、関連付けに基づく更新を防ぐために固定化
命令型ブロック内の変数を命令型スコープに対してローカルに
リストとディクショナリを分離
1.簡略化された list@level 構文
2.ランクのみが異なるパラメータを持つオーバーロードされた関数を不正とする
オーバーロードされた関数は、次のような理由で問題となることがあります。
グラフ内の UI ノードによって示されるオーバーロードされた関数が、実行時に実行されるオーバーロードと同じではない場合がある
メソッドの解決にはコストがかかり、オーバーロードされた関数に対してはうまく機能しない
オーバーロードされた関数の複製動作を理解するのは困難である
例として BoundingBox.ByGeometry
を見てみましょう(古いバージョンの Dynamo にオーバーロードされた関数が 2 つあります)。1 つは単一の値引数を取り、もう 1 つはジオメトリのリストを引数として受け取っています。
2.0 では、この理由により、パラメータの基数のみが異なるオーバーロードの関数を禁止しています。つまり、パラメータの数と種類は同じであるが、ランクのみが異なる 1 つ以上のパラメータを持つオーバーロード関数の場合、最初に定義されたオーバーロードが常に優先され、残りはコンパイラによって破棄されます。この簡略化を行う主な利点は、関数候補を選択するためのクイック パスを持つことで、メソッド解決ロジックを単純化することです。
2.0 のジオメトリ ライブラリでは、BoundingBox.ByGeometry
の例の最初のオーバーロードは廃止され、2 番目のオーバーロードは保持されています。そのため、ノードを複製する意図がある場合、つまり最初のオーバーロードのコンテキストで使用する場合は、最短(または最長)のレーシング オプションで使用するか、複製ガイドを含むコード ブロックで使用する必要があります。
この例では、上位ランクのノードは複製された呼び出しと複製されていない呼び出しの両方で使用できるため、下位ランクのオーバーロードよりも常に優先されることがわかります。したがって、経験則として、**ノード作成者は、下位ランクのオーバーロードを削除して上位ランクのメソッドを優先することをお勧めします。**これにより DesignScript コンパイラは常に上位ランクのメソッドを最初に検出された唯一のメソッドとして呼び出します。
例:
次の例では、関数 foo
の 2 つのオーバーロードが定義されています。1.x では、実行時にどのオーバーロードが実行されるかが曖昧になっています。ユーザーは、2 番目のオーバーロード foo(a:int, b:int)
が実行されることを期待するかもしれません。その場合、メソッドは 3 回複製され、10
の値を 3 回返すことが期待されます。実際には、list パラメータを持つ最初のオーバーロードが代わりに呼び出されるため、返されるのは 10
の値 1 つです。
2.0 では 2 番目のオーバーロードが省略されます。
2.0 では、常に最初に定義されたメソッドが他のメソッドよりも優先されます。つまり、先着順になるということです。
次の各ケースでは、最初に定義されたオーバーロードが考慮されます。これはパラメータのランクではなく単に関数の定義順序に基づいています。しかしユーザー定義ノードや Zero-Touch ノードでは、ランクの高いパラメータを持つメソッドを優先することをお勧めします。
3.すべての UI ノードを静的メソッドにコンパイルする
Dynamo 1.x では、UI ノード(非コード ブロック)は、それぞれインスタンス メソッドとプロパティにコンパイルされました。たとえば、Point.X
ノードは pt.X
にコンパイルされ、Curve.PointAtParameter
は curve.PointAtParameter(param)
にコンパイルされていました。しかし、この動作には 2 つの問題がありました。
A.UI ノードが表す関数は、実行時に実行される関数と同じとは限らない
典型的な例は、Translate
ノードです。Geometry.Translate
、Mesh.Translate
、FamilyInstance.Translate
など、同じ数とタイプの引数を取る複数の Translate
ノードがあります。ノードはインスタンス メソッドとしてコンパイルされるため、Geometry.Translate
ノードに FamilyInstance
を渡すと、実行時に FamilyInstance
の Translate
インスタンス メソッドへの呼び出しがディスパッチされるため、それでも機能してしまいます。この場合、ノードが言った内容を実行しておらず、明らかにユーザーに誤解を与えていました。
B.2 つ目の問題は、インスタンス メソッドが異種配列で機能しないこと
実行時に、実行エンジンはどの関数にディスパッチするかを見つける必要があります。入力がリスト(list.Translate()
など)の場合、リスト内の各要素とその型でルックアップ メソッドを実行するのはコストがかかるため、メソッド解決ロジックでは、ターゲット型が最初の要素の型と同じであると想定し、その型で定義されているメソッド Translate()
を検索しようとします。その結果、最初の要素型がメソッドのターゲット型と一致しない場合(または、null
型または空のリストであった場合)、一致する他の型がリスト内にあっても、リスト全体が失敗します。
たとえば次のように、[Arc, Line]
タイプのリスト入力が Arc.CenterPoint
に渡された場合、結果には想定通り円弧の中心点と線の null
値が含まれます。ただし、順序が逆の場合は、最初の要素がメソッド解決チェックに失敗したため、結果全体が null になります。
Dynamo 1.x: メソッドの解決チェックで、入力リストの最初の要素のみをテストする
2.0 では、これらの問題はいずれも UI ノードを静的プロパティと静的メソッドとしてコンパイルすることで解決されます。
静的メソッドを使用すると、実行時メソッドの解決がより簡単になり、入力リスト内のすべての要素が反復処理されます。例:
foo.Bar()
(インスタンス メソッド)セマンティックでは、foo
の型をチェックし、それがリストであるかどうかもチェックしてから、候補の関数と照合する必要があります。これはコストがかかります。一方、Foo.Bar(foo)
(静的メソッド)セマンティックで照合する必要があるのは、パラメータ型 foo
を持つ関数 1 つのみです。
こちらが 2.0 での挙動になります。
UI プロパティ ノードが静的ゲッターにコンパイルされます。エンジンはプロパティごとに静的なバージョンのゲッターを生成します。たとえば、
Point.X
ノードは静的ゲッターPoint.get_X(pt)
にコンパイルされます。静的ゲッターは、そのエイリアスPoint.X(pt)
を使用して Code Block ノードで呼び出すこともできます。UI メソッド ノードが静的バージョンにコンパイルされます。エンジンはノードに対応する静的メソッドを生成します。たとえば、
Curve.PointAtParameter
ノードはcurve.PointAtParameter(parameter)
ではなくCurve.PointAtParameter(curve: Curve, parameter:double)
にコンパイルされます。
注: この変更によるインスタンス メソッドのサポートは削除されていないため、上記の例の pt.X
や curve.PointAtParameter(parameter)
など、CBN で使用されている既存のインスタンス メソッドは引き続き機能します。
この例は、以前は 1.x で機能していました。グラフは point.X;
にコンパイルされ、点オブジェクトで X
プロパティが検索されていました。2.0 では、コンパイルされたコードとして失敗します。Vector.X(point)
は Vector
型のみを要求するためです。
利点:
一貫性がある/理解しやすい: 静的メソッドは、どのメソッドが実行時に実行されるかに関する曖昧さを解消します。メソッドは、ユーザーが呼び出されると想定しているグラフで使用される UI ノードと常に一致します。
互換性: コードとビジュアル プログラムの間には、より優れた相関関係があります。
指示: ノードに異種のリスト入力を渡すと、ノードで受け入れられる型の場合は null 以外の値、ノードを実装しない型の場合は null 値になるようになりました。結果の予測可能性が向上し、ノードに対してどのタイプが許容されるかが示されるようになります。
注意事項: オーバーロードのメソッドによる曖昧さが解決されない
解決された問題:
静的メソッド セマンティックへの移行により、関連する 2.0 言語の変更としてここで言及する価値のある次の副作用がもたらされました。
1.ポリモーフィック動作の喪失:
ProtoGeometry
の TSpline
ノードの例を考えてみましょう(TSplineTopology
は基本の Topology
型から継承されていることに注意してください)。以前にインスタンス メソッド object.Edges
にコンパイルされた Topology.Edges
ノードは、静的メソッド Topology.Edges(object)
にコンパイルされるようになりました。以前の呼び出しは、オブジェクトの実行時型に対するメソッドのディスパッチ後に、派生クラス メソッド TsplineTopology.Edges
にポリモーフィックで解決されます。
一方、新しい静的動作は、基本クラス メソッド Topology.Edges
を呼び出すしかありません。その結果、このノードは、型 TSplineEdge
の派生クラス オブジェクトではなく、Edge
オブジェクトである基本クラスを返しました。
これは、TSplineEdges
を期待していた下流の TSpline
ノードに障害が発生し始めたことによるリグレッションでした。
この問題は、メソッド ディスパッチのロジックに実行時チェックを追加して、メソッドの最初のパラメータのタイプまたはサブタイプに対してインスタンス タイプをチェックすることで修正されました。入力リストの場合、メソッドのディスパッチを簡略化して、最初の要素の型だけをチェックするようにしました。したがって、最終的な解決策は、部分的に静的なメソッド検索と部分的に動的なメソッド検索の間の妥協案となりました。
2.0 の新しいポリモーフィック動作:
このケースでは、最初の要素 a
は TSpline
であるため、実行時に呼び出されるのは派生メソッド TSplineTopology.Edges
です。その結果、基本の Topology
型 b
には null
が返されます。
2 番目のケースでは、一般的な Topology
型 b
が最初の要素であるため、基本 Topology.Edges
メソッドが呼び出されます。Topology.Edges
は派生の TSplineTopology
型である a
も入力として受け入れるようになっているため、a
と b
の両方の入力に対して Edges
を返します。
2.冗長な外部リストの生成によるリグレッション
インスタンス メソッドと静的メソッドの間には、複製ガイドの動作に関する主な違いが 1 つあります。インスタンス メソッドでは、複製ガイドを含む単一値の入力はリストにプロモートされませんが、静的メソッドではプロモートされます。
直積レーシングと単一のサーフェス入力がある Surface.PointAtParameter
ノードと、u
および v
パラメータ値の配列の例を考えてみましょう。インスタンス メソッドは次のようにコンパイルされます。
結果は、点の 2D 配列になります。
静的メソッドは次のようにコンパイルされます。
重複した最も外側のリストを持つ点の 3D リストが作成されます。
この UI ノードを静的メソッドにコンパイルする副作用により、このような既存のユースケースでリグレッションが発生する可能性があります。この問題は、複製ガイド/レーシングと共に使用する場合に、リストへの単一値入力のプロモートを無効にすることで解決されました(次の項目を参照)。
4.複製ガイド/レーシングによる無効なリストのプロモート
1.x では、単一値がリストにプロモートされるケースが 2 つありました。
下位ランクの入力が、上位ランクの入力を必要とする関数に渡された場合
下位ランクの入力が、同じランクを期待する関数に渡されたが、入力引数が複製ガイドで修飾されているか、レーシングが使用されている場合
2.0 では、このようなシナリオでリストのプロモートを防ぐことで、後者の場合をサポートしないようになりました。
次の 1.x のグラフでは、y
と z
それぞれの複製ガイド 1 レベルにつき、配列のプロモートがランク 1 つ分強制されているため、結果はランク 3 (x
、y
、z
各 1 つ)になっています。その代わり、単一値入力の複製ガイドの存在によって、結果にレベルが追加されることはあまり明確ではないため、ユーザーは結果がランク 1 であることを予想します。
Dynamo 1.x: 点の 3D リスト
2.0 では、単一値の引数 y
と z
のそれぞれに複製ガイドが存在しても、x
の入力 1D リストと同じ寸法を持つリストがプロモートされません。
Dynamo 2.0:点の 1D リスト
冗長な外部リストを生成する静的メソッドのコンパイルによって引き起こされた上記のリグレッションも、この言語変更によって対処されました。
上記と同じ例を続けると、次のような静的メソッド呼び出しが見つかりました。
この呼び出しは、Dynamo 1.x で点の 3D リストを作成しました。これは、複製ガイドで使用されるときに、最初の単一値の引数サーフェスがリストにプロモートするために発生しました。
Dynamo 1.x: 複製ガイドで引数のリストをプロモートする
2.0 では、複製ガイドまたはレーシングで使用する場合に、リストへの単一値引数のプロモートを無効にしました。したがって、以下の呼び出しでは、
サーフェスがプロモートされないため、2D リストを返すのみとなります。
Dynamo 2.0: 複製ガイドで単一値引数のリストのプロモートが無効になる
この変更により、冗長なリスト レベルの追加が削除され、静的メソッドのコンパイルへの移行によって引き起こされるリグレッションも解決されるようになりました。
利点:
**読みやすさ: ** 結果がユーザーの期待に沿っており、理解しやすい
**互換性: ** UI ノード(レーシング オプション付き)と CBN の複製ガイドを使用すると、互換性のある結果が得られる
一貫性:
インスタンス メソッドと静的メソッドの一貫性がある(静的メソッド セマンティックの問題を修正)
入力を持つノードと既定の引数を持つノードは一貫性を持って動作する(以下を参照)
5.自動調整更新を防ぐために、Code Block ノードの変数は固定化
DesignScript は従来より、自動調整プログラミングと命令型プログラミングという 2 つのプログラミング パラダイムをサポートしています。自動調整コードは、変数が互いに依存関係を持つプログラム ステートメントから依存関係グラフを作成します。変数を更新すると、この変数に依存する他のすべての変数の更新をトリガーできます。つまり、自動調整ブロック内のステートメントの実行順序は、その順序ではなく、変数間の依存関係に基づいています。
次の例では、コードの実行順序は 1 行目 -> 2 行目-> 3 行目-> 2 行目です。b
は a
に依存しているため、a
が 3 行目で更新されると、実行は再び 2 行目にジャンプして、a
の新しい値で b
を更新します。
これとは対照的に、同じコードが命令型コンテキストで実行される場合、ステートメントは順番にトップダウン フローで実行されます。したがって、命令型コード ブロックは、ループや if-else 条件などのコード構造を順次実行するのに適しています。
自動調整更新の曖昧さ:
1.循環依存のある変数:
一部では、次のケースのように、変数間の循環依存関係が明瞭ではないことがあります。このような場合、コンパイラがサイクルを静的に検出できないため、実行時サイクルが無期限になる可能性があります。
2.自己依存変数:
変数がそれ自体に依存している場合、その値は蓄積されるのでしょうか、それとも更新のたびに元の値にリセットされるのでしょうか?
このジオメトリの例では、立方体 b
はそれ自体と円柱 a
に依存しています。スライダーを動かした場合、穴はブロックに沿って移動するのでしょうか? それともスライダーの位置が更新されると、そのたびにパスに沿って複数の穴をなぞるという累積効果を生み出すのでしょうか?
3.変数のプロパティの更新:
4.関数の更新:
これまでの経験から、自動調整更新は、ノードベースのデータフロー グラフ コンテキストの Code Block ノードでは役に立たないことがわかりました。ビジュアル プログラミング環境が利用できるようになる前は、オプションとして考えられるのはプログラム内の一部の変数の値を明示的に変更することのみでした。テキストベースのプログラムでは、変数の更新履歴がすべて記録されますが、ビジュアル プログラミング環境では、変数の最新の値のみが表示されます。
使用するのが一部のユーザーであっても、無意識のうちに使用される可能性があり、利益よりも害を及ぼす可能性が高いと思われます。したがって 2.0 では、変数を固定にすることで Code Block ノードの使用における関連付けを非表示にする一方で、自動調整更新は DS エンジンのみのネイティブ機能として引き続き保持することにしました。これは、ユーザーのスクリプト エクスペリエンスを簡略化するという考えで行われたもう 1 つの変更です。
コード ブロック内でもリストのインデックス作成は引き続き許可される
リストのインデックス作成には例外が設けられており、2.0 ではインデックス演算子の割り当てによって引き続き許可されています。
次の例では、リスト a
が初期化されますが、後でインデックス演算子の代入で上書きできること、a
に依存する変数が c
の値によって自動調整で更新されることがわかります。また、ノードのプレビューには、1 つまたは複数の要素の再定義後に更新された a
の値が表示されます。
6.命令型ブロック内の変数は命令型ブロック スコープに対してローカルに
複雑な言語間の更新シナリオを無効にするために、必須のスコープ ルールを 2.0 に変更しました。
Dynamo 1.x では、次のスクリプトの実行シーケンスは 1 行目 -> 2 行目 -> 4 行目 -> 6 行目 -> 4 行目の順となり、変更は外部言語スコープから内部言語スコープに伝達されます。y
は外側の自動調整ブロックで更新され、命令型ブロック内の x
は y
に依存しているため、制御は外側の関連付けられたプログラムから 4 行目の命令型言語に移ります。
次の例の実行シーケンスは、1 行目 -> 2 行目 -> 4 行目 -> 2 行目の順で、変更は内部言語スコープから外部言語スコープに伝達されます。
上記のシナリオは言語間更新に関するものですが、自動調整更新と同様に、Code Block ノードではあまり有用ではありません。複雑な言語間更新シナリオを無効にするために、命令スコープの変数をローカルにしました。
Dynamo 2.0 では、次の例のようになります。
x
の命令型ブロックでの定義が命令型スコープに対してローカルになりました外側のスコープの
x
とy
の値は、それぞれ1
と2
のままです
命令型ブロック内のローカル変数は、その値が外部スコープでアクセスされる場合は、すべて返す必要があります。
次の例を考えてみましょう。
y
が、命令型のスコープ内にローカルでコピーされます命令型スコープに対する
x
のローカル値は4
です外側のスコープで
y
の値を更新すると、言語間の更新のためにx
が引き続き更新されますが、変数は固定されているため、2.0 のコード ブロックでは無効になります外側の自動調整スコープの
x
とy
の値は、それぞれ1
と2
のままです
7.リストとディクショナリ
Dynamo 1.x では、リストとディクショナリは 1 つの統合コンテナで表され、整数インデックスと非整数キーの両方でインデックス付けができました。次の表は、2.0 でのリストとディクショナリの分離と、新しいディクショナリ データ型のルールをまとめたものです。
リストの初期化
a = {1, 2, 3};
a = [1, 2, 3];
空のリスト
a = {};
a = [];
ディクショナリの初期化
同じディクショナリに動的に追加できます :
新しいディクショナリのみ作成できます:
a = {};
a = {“foo” : 1, “bar” : 2};
a[“foo”] = 1;
b = {“foo” : 1, “bar” : 2, “baz” : 3};
a[“bar”] = 2;
a = {};
// 空のディクショナリを作成します
a[“baz”] = 3;
ディクショナリのインデックス作成
キーのインデックス作成
インデックスの構文は同じままです
b = a[“bar”];
b = a[“bar”];
ディクショナリ キー
任意のキー タイプが有効
文字列キーのみ有効
a = {};
a = {“false” : 23, “point” : 12};
a[false] = 23;
a[point] = 12;
新しい[]
リスト構文
[]
リスト構文2.0 では、リスト初期化構文は中括弧 {}
から角括弧 []
に変更されました。すべての 1.x スクリプトは、2.0 で開くと、新しい構文に自動的に移行されます。
Zero-Touch ノードの既定の引数属性に関する注意事項:
自動移行は、既定の引数属性で使用される古い構文では機能しないことに注意してください。ノードの作成者は、必要に応じて、既定の引数属性 DefaultArgumentAttribute
で新しい構文を使用するために、Zero-Touch メソッド定義を手動で更新する必要があります。
インデックス作成に関する注意事項:
新しいインデックス作成動作は、特定のケースで変更されています。[]
演算子を使用して、インデックス/キーの任意のリストでリスト/ディクショナリにインデックスを付けると、インデックス/キーの入力リストのリスト構造が保持されるようになりました。以前は、常に値の 1D リストが返されていました。
ディクショナリの初期化構文:
ディクショナリの初期化のための {}
(中括弧構文) は以下の形でのみ使用できます。
キーと値のペアの形式で、<key>
には文字列のみが許可され、複数のキーと値のペアはコンマで区切られます。
Dictionary.ByKeysValues
Zero-Touch メソッドは、キーと値のリストをそれぞれ渡し、複製ガイドなどの Zero-Touch メソッドを使用するためのすべての機能を備えているため、ディクショナリ初期化におけるより用途の広い方法として使用できます。
ディクショナリの初期化構文に任意の式を使用しなかった理由
ディクショナリのキー値初期化構文でキーに任意の式を使用するというアイデアを実験したところ、特に {keys : vals}
(keys
と vals
のどちらもリストを表現)などの構文が複製などのその他の DesignScript 言語機能に干渉し、Zero-Touch 初期化ノードから異なる結果を生成する場合に混乱を招く可能性があることがわかりました。
たとえば、次のステートメントのように、期待される動作を定義するのが難しいケースが他にもある可能性があります。
識別子だけでなく、複製ガイドの構文などをミックスに追加することは、言語の単純さという考え方に反します。
将来的にはディクショナリのキーを拡張して任意の式をサポートする_可能性があります_が、システムの性能を落として理解しやすくするよりは、多少複雑になったとしても、他の言語機能との相互作用に一貫性を持たせることで理解しやすくする必要があります。別の方法として、いつでも Dictionary.ByKeysValues(keyList, valueList)
メソッドを使用することができると考えると、これにはそれほど無理はありません。
Zero-Touch ノードとのインタラクション:
1..NET ディクショナリを返す Zero-Touch ノードは、Dynamo ディクショナリとして返されます。
2.Multi-Return ノードはディクショナリとしてプレビューされます
3.Dynamo ディクショナリは、.NET ディクショナリを受け入れる Zero-touch ノードに入力として渡すことができます
Multi-Return ノードでのディクショナリのプレビュー
ディクショナリは、順序付けされていないキーと値のペアです。この考え方に従い、ディクショナリを返すノードのキーと値のペアのプレビューは、ノードの戻り値の順序で順序付けされることは保証されません。
ただし、MultiReturnAttribute
が定義されている Multi-Return ノードには例外を設けました。次の例では、DateTime.Components
ノードが「Multi-Return」ノードであり、ノードのプレビューには、そのキーと値のペアがノードの出力ポートと同じ順序で反映されます。これは出力がノード定義の MultiReturnAttribute
に基づいて指定される順序でもあります。
Last updated