フローチャートが書けない

昔、講義でフローチャートを書かされたような記憶はあるが、
全く自慢にならないが、今「フローチャート書いて」と言われても書ける自信が全くない。
開始が四角で分岐が菱型だったけ?線引いてYes/Noみたいな。そんな感じ?

とはいえ、ドキュメントでフローを表現したいことは間々あるわけで、じゃあどうしているの?
という問いに対しては「擬似コードで良くね?」と答えたい。

Wikipedia見たらこんなフローチャートがあった。

f:id:s-shin:20150329214131p:plain

フローチャート - Wikipedia

この図もそうであるが、基本的にフローチャートは、擬似コードで書ける。

function sumFrom1To10() {
  var n = 1;
  var s = 0;
  while (n < 10) {
    s += n;
    n += 1;
  }
  return s;
}

JavaScriptで書いてみたが、言語は何でも、それこそ架空の言語でも良いと思う。
書き方もあえてフローチャートに合わせてwhile使ってるが、for使えばもっとシンプルに書ける。

...

というようなことを考えていたら、フローチャートは過去の遺物的は議論は既に結論が出ている話題のようだ。

フローチャート不要論 - Google検索

...

では、フローを表現する図は不要なのか、という言われると、そうでもない。
例えば、UMLのシーケンス図は、擬似コード化しづらいので重宝する。
もちろんシーケンス図も完璧ではないが、PlantUML使えばテキストで書けるし、不満は少ない。


オチは特に無い。

PHPの小ネタ: タイプヒンティングの罠

タイプヒンティングとは

PHP5からタイプヒンティングという似非タイプチェック機能が使えるようになっています。

<?php
interface Runnable
{
    public function run();
}

class Foo implements Runnable
{
    public function run()
    {
        echo 'Foo', "\n";
    }
}

class Bar
{
    public function run()
    {
        echo 'Bar', "\n";
    }
}

function run(Runnable $runner)
{
    $runner->run();
}

run(new Foo);
run(new Bar);
Foo
PHP Catchable fatal error:  Argument 1 passed to run() must implement interface Runnable, instance of Bar given

なるほど中々悪くなさそうな機能です。 が、このタイプヒンティングという機能には、色々と罠が潜んでいます。

スカラー型には使えない

ちゃんとマニュアルを読みましょうという話ですが、

タイプヒントは int や string といったスカラー型には使えません。 また、リソース や トレイト も使えません。

http://php.net/manual/ja/language.oop5.typehinting.php

と書かれています。

<?php
function add(int $a, int $b) // NG
{
    return $a + $b;
}

ついついやりたくなるんですけどね…。

nullは渡せない、が渡せないこともない

何言っているのかというと、こういうことです。

<?php
function echoTimestamp(DateTime $dt)
{
    echo ($dt ? $dt->getTimestamp() : 0), "\n";
}

echoTimestamp(null);
PHP Catchable fatal error:  Argument 1 passed to echoTimestamp() must be an instance of DateTime, null given,

なるほど、nullは渡せないのか! と思いきや。

<?php
function echoTimestamp(DateTime $dt = null)
{
    echo ($dt ? $dt->getTimestamp() : 0), "\n";
}

echoTimestamp(null);
0

デフォルト引数にnullを与えている場合は、null値を引数に渡せます。なんじゃそりゃ。

しかし、デフォルトのパラメータの値として NULL を使用した場合は、後から任意の値を引数に指定できるようになります。

http://php.net/manual/ja/language.oop5.typehinting.php

デフォルト引数が無いときにnull値を与えられないというのは、メソッド内部でnullかどうかで分岐してないということが保証されるので、それはそれで良いのかな*1と良心的に解釈できますが、デフォルト引数nullの仕様は完全に蛇足な気がします。

<?php
function addSeconds(DateTime $dt = null, $seconds = 0)
{
    if (is_null($dt)) {
        $dt = new DateTime('now');
    }
    return $dt->add(new DateInterval("PT{$seconds}S"));
}

$dt = new DateTime('now');
echo $dt->format('H:i:s'), "\n";
echo addSeconds($dt, 300)->format('H:i:s'), "\n";
echo addSeconds(null, 300)->format('H:i:s'), "\n";

全部にデフォルト引数与えるの、なんか違わない?引数なしで呼べるけど意図した使い方じゃないよね、という…。

所感

タイプヒンティングは、nullが来ないことを保証されているのだとポジティブに考えて、上手に使うのが良いのかと思います。

hacklangではもっと厳密に型を宣言できるようなので、一度試してみたい所です。

*1:nullでの分岐をしたくなるシチュエーションはそれなりにありますが、そういうことをするとメソッドブラックボックス度は上がるのでそれが矯正されるなら良くかなという

structの関数プロパティとメソッドの挙動

package main

import "fmt"

type OpFunc func(int, int) int

type Operation struct {
	// associateされていないのでOperationのプロパティ・メソッドへのアクセスは出来ない。
	Do1 OpFunc
	// 以下コメントを外すと "type Operation has both field and method named Do2"
	//Do2 OpFunc
}

func (op Operation) Do2(a, b int) int {
	return op.Do1(a, b)
}

func main() {
	op := &Operation{
		Do1: func(a, b int) int {
			return a + b
		},
	}
	fmt.Println(op.Do1(1, 2), op.Do2(3, 4))
}

http://play.golang.org/p/4ytA1cOJ1d