IT ニュース&コラム 2020/ 3/ 2 通巻807号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ■■ 手続き型プログラミングと宣言型プログラミングを使い分ける(2) ■■ 宣言型プログラミングを、手続き型のプログラミング言語で行ったとき、書く順番に 影響してしまうという問題の解決方法として、プロパティやメソッドにデータ定義を 書く方法を前回(通巻803号)に紹介しました。 今回は、他にも発生する問題について 紹介しその対策方法も紹介します。 前回のおさらいを軽くします。 言語は TypeScript です。 var taro = { name: "Taro", age: 21 } var jiro = { name: "Jiro", age: 20 } var family = [ taro, jiro ] プロパティやメソッドにデータ定義しないとこのようになるのですが、 これでは taro の定義を family の定義の下に書くことはできません。 class DataClass { Family() { return [ this.Taro(), this.Jiro() ] } Taro() { return { name: "Taro", age: 21 } } Jiro() { return { name: "Jiro", age: 20 } } } このようにプロパティやメソッドにデータ定義を書くことで、書く順番が自由になりました。 しかし、処理を実行するプロパティやメソッド(以後、関数と呼ぶ)は、副作用がある 可能性がります。 関数の副作用とは、状態 (値) が変化してしまうことです。 副作用が必要な場合もありますので一概に関数の副作用が悪いわけではないですが、 データ定義において副作用は有害です。 なぜなら、関数を呼び出すタイミングによって データの内容が変わってしまうからです。 たとえば、StartTime というデータを 処理を行っている現在の日時と定義したとしましょう。 StartTime() { return new Date(); } この StartTime は参照する(呼び出す)だびに値が変わります(精度は1ミリ秒)。 もし、StartTime から現在の日時までの経過時間 Elapsed を定義すると、 Elapsed() { return (new Date()).getTime() - this.StartTime().getTime(); } となりますが、これでは期待通りの値が返りません。 なぜなら、new Date が連続して 2回呼ばれるために、長い時間の処理が行われても 0〜1ミリ秒しか返さないからです。 他にも副作用がある関数の例を挙げます。 オブジェクトの生成です。 MyObject() { return new MyClass(); } これでは、if ( MyObject() == MyObject() ) が常に false になってしまいます。 このような副作用の問題を解決するには、関数で行われる処理を一度だけ実行し、その返り値を 2回目以降の呼び出しでも返すようにすることです。 一度だけ呼び出す関数とも呼ばれます。 一度だけ呼び出す関数は、次のように定義します。 StartTime = CallOnceFunction(() => { return new Date(); }); CallOnceFunction の定義は、クロージャーを使う場合は、次のようになります。 function CallOnceFunction( calleeFunction: () => ReturnType ) { let called = false; let result: ReturnType = {} as ReturnType; return function() { if ( ! called ) { result = calleeFunction(); called = true; } return result; }; }; ただし、この定義では問題があります。 それは、循環参照すると無限ループしてしまうことです。 循環参照とは、たとえば、A の定義に B の入力があり、B の定義に A の入力があることです。 にわとりが先かたまごが先かという状態です。 A() { return B() + 1; }); B() { return A() - 1; }); または、 class MyClass { ID: number = 0; } A = CallOnceFunction(() => { let object = new MyClass(); object.ID = this.B().ID + 1; // 循環参照 return object; }); B = CallOnceFunction(() => { let object = new MyClass(); object.ID = this.A().ID - 1; // 循環参照 return object; }); 循環参照の原因は、設計ミスの場合と、定義と異なる設計によって回避が必要な場合が ありますが、どちらにしてもデータの定義ができない状態です。 最終的には定義できる 状態に修正して動かすわけですが、循環参照という問題があることをユーザーが知ることが できるようにしなければ、修正が遅れてしまいます。 Maximum call stack size exceeded エラーになりますが循環参照エラーになっているとは熟練者しか気づかないでしょう。 次のように定義すれば、循環参照の問題があることをユーザーがすぐに知ることができます。 function CallOnceFunction( calleeFunction: () => ReturnType ) { let called = false; let calling = false; let result: ReturnType = {} as ReturnType; return function() { if ( ! called ) { if ( calling ) { throw new Error( "circular reference" ); } calling = true; result = calleeFunction(); calling = false; called = true; } return result; }; }; 循環参照のコードの書き方によっては、次のコンパイルエラーになることがあります。 '__Symbol__' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022) もう1つ問題がありますが、それは次回説明します。 ■■ 注目ニュース 一覧 ■■ ◇ macOSを標的にしたマルウェアの検出数がWindowsを標的にしたマルウェア検出数を初めて上回る。 https://gigazine.net/news/20200213-malware-threats-macs-outpace-windows/ … なんとついに mac のほうがマルウェアが多くなってしまった。 ◇ 楽天の送料無料化、3月18日開始に変更なし。公取委緊急停止命令受けてもなお。 https://japan.cnet.com/article/35150051/ https://japan.cnet.com/article/35150037/ … これはアマゾンよりひどい。 ◇ Windows 10のライブタイル機能が廃止へ。 https://gigazine.net/news/20200226-windows-10-live-tile/ … すべてのプログラムとライブタイルの2つの系列を1つに。 ◇ ストレスを減らして燃え尽き症候群を防ぐために心理学者が示す5つのヒント。 https://gigazine.net/news/20200210-reduce-stress-at-work/ … 燃え尽き症候群の直し方。いくつかあるうち、まずは寝たほうがいいと思う。 ◇ 交渉はかえって裏目に回るとの指摘、それではやむをえず交渉をする場合は一体どうすればいいのか。 https://gigazine.net/news/20200211-better-negotiation-hard-soft-approach/ … 交渉して勝つより交渉しないで負けた気になっても後々良いこともある。 ◇ 週休2日制はどのようにして始まって広まったのか? https://gigazine.net/news/20200211-history-two-day-weekend/ … いろいろあるが欠勤が減ったことが大きいかったようだ。 ◇ 週4日労働制の導入はどのように世界中の企業で実施されているのか? https://gigazine.net/news/20200226-four-day-workweek-global/ … 週4日制になると子育てにおける男女平等が実現できそう。 ◇ ゲーム雑誌、電撃PlayStation が定期刊行を停止へ。25年続いたプレステ専門誌。 https://japan.cnet.com/article/35149906/ … 雑誌形態のみ停止。 ◇ 全てのメロディの著作権を取得するという試みがなぜ未来の音楽を守ることになるのか? https://gigazine.net/news/20200212-copyrighted-melody/ … 総当たり攻撃のように全てのメロディの権利を取ってしまう。でもこれはただの変換。 ◇ 顔をプリントしたマスク、着けたまま顔認識でロック解除も。デザイナー考案。 https://japan.cnet.com/article/35149601/ … スマホぐらいのセキュリティ対象ならこれで成功してもいいのでは。 ◇ 消滅したウェブサイトをインターネットアーカイブから直接表示できる機能がウェブブラウザBraveに搭載される。 https://gigazine.net/news/20200226-brave-show-404-web-page/ … 消されたページも自動的にアーカイブされたサーバーから閲覧できる。 ◇ AmazonやFacebookが新型コロナウイルス感染症の予防や完治をうたう商品や広告を削除へ。 https://gigazine.net/news/20200227-amazon-facebook-reject-coronavirus-cure/ … これは正しい対応。 ◇ アマゾンのベゾスCEO、気候変動対策に1兆円超の基金 Bezos Earth Fund 設立。 https://japan.cnet.com/article/35149534/ https://japan.cnet.com/article/35149649/ … 地球温暖化阻止に本気になるかどうか。税金対策なのでは。 ◇ 無料の衛星データプラットフォーム Tellus がVer2.0に。アプリが買えるストア機能も。 https://japan.cnet.com/article/35149978/ … グーグルマップだけじゃない。 ◇ ついにFirefoxがDNSとの通信を暗号化する DNS over HTTPS をデフォルトで有効にすると発表。 https://gigazine.net/news/20200226-firefox-dns-over-https-default-us/ … グーグルには筒抜け。 ■■ ソフトウェアデザイン館 Sage Plaisir 21 ■■ ホームページ >>> http://www.sage-p.com/ メルマガ >>> http://www.mag2.com/m/0000083983.html ブログ >>> http://blog.livedoor.jp/sage_p/ ツイッター >>> http://twitter.com/Ts_Neko ダウンロード >>> http://www.sage-p.com/freesoft.htm サポート掲示板 >>> http://www.sage-p.com/kg_ban09/z6037C8.cgi 東日本大震災 >>> http://www.sage-p.com/saigai.html メール >>> ts-neko◇sage-p.com ←◇を@に変えてください 緊急メールは件名に「うどんメール」を付けてください。 このメルマガの登録・解除 - http://www.mag2.com/m/0000083983.htm