Hatena2008-02-19
code:hatena
<body>
*1203387809*おなかがいたい(T/O)
*1203397334*HARIBO
id:hayamiz 先輩の大好物HARIBOがラボの下のコンビニで売っていたので試しに買ってみた。歯ごたえのあるグミだ。これであこがれの先輩に一歩近づけたかな?
-----
一つのHARIBOを消費するまでに掛かる時間を計ってみたら17分だった。
こんな言葉がある。
「ハッカーには痩せている人と太っている人がいる。前者はコーディングにのめり込むと寝食を忘れるタイプ。後者はコーディングにのめり込むと寝食を忘れるが、常に口に物が入っているタイプ。」
僕は後者なのでメタボ対策が必須なのだけども、HARIBOは単位時間あたりのカロリーが小さいのでいいかもしれない。前はフリスカーだったけど、さすがに1日に2箱のフリスクを食べたら体臭が変わった気がして怖くなった。
*1203399380*Re: たとえ重複していても、一度分割したものはまとめるな!
>
最初、擬似コードを書く時点で、この5パターン以外ありえないことはすぐにわかります。そして、それぞれについて解法を考えます。しかし、それをやりながら、「1つにまとめられるんじゃない?」と欲を出すと、失敗します。難しくて分割したなら、まとめちゃいけません!
<<
これ「重複していても *未来永劫* まとめてはいけない」という意味ではないですよね?とかくこういうキャッチフレーズは背景を離れて一人歩きしがちなので勘違いをする人が出てくるのではないかとちょっと心配になりました。
もともと「重複するコードは一つにまとめるべき」という話は「同じ処理があちこちに重複していると、仕様が変更されたときに修正する箇所もあちこちに散らばっているので修正コストが高い&うっかり修正忘れをするリスクが高い」という問題があるという話なので、yukobaさんのようなケースで「実装中に『これ重複をまとめられるんじゃない?』とか考えるべきではない」というのには諸手を挙げて賛同です。でも、もしこれが将来「h == zoneMax」と「else」の共通部分に仕様変更が入る可能性があるなら、実装し終わってうまく動くことを確認した後ででも一つにまとめることを考えた方がいいですよね?
ようは「実装とリファクタリングを同時にやろうとすると失敗する」ということと、「重複部分はまとめるべき」という教義にも前提条件があるので「前提条件をみたさないなら無視してOK」ということですね。
*1203400566*Javathisはどこからコレなのか Javaで下のコードを実行すると何が表示されるでしょう。
|java|
public class ScopeOfThis {
public int a = 100;
public ScopeOfThis() {
System.out.println("first:" + a);
class Foo {
public int a = this.a++;
public Foo(){
int a = this.a++;
System.out.println("inside(a):" + a);
System.out.println("inside(this.a):" +this.a);
}
}
new Foo();
System.out.println("last:" + a);
}
public static void main(String[] args) {
new ScopeOfThis();
}
}
||<
いきなり答えだと考えるチャンスを奪ってしまうのでスポイラー代わりに
Pythonで似たようなことを書いてみました。
下のように書くと:
|python|
class ScopeOfThis(object):
a = 100
def __init__(self):
print "first:", self.a
class Foo(object):
a = self.a
self.a += 1
def __init__(self):
a = self.a
self.a += 1
print "inside(a):", a
print "inside(self.a)", self.a
Foo()
print "last:", self.a
ScopeOfThis()
||<
こう表示されます:
||
first: 100
inside(a): 100
inside(self.a) 101
last: 101
||<
-----
解答篇:
Javaで上のコードを実行すると下のように表示されます。
||
first:100
inside(a):0
inside(this.a):1
last:100
||<
Fooのフィールドを初期化する時点ですでにthisはFooのインスタンスを指しているわけですね~。
疑問点
- public int a = this.a++;をpublic int a = a++;にするとコンパイルエラーになる。
*1203412430*JavaとPythonのフィールド初期化タイミングの違い
>
インナークラスのthisが何をさすかはそのままじゃん。
<<
んー、この感覚の違いが何から生まれるか考えた。
|java|
public class TimingOfInitialize {
public static Foo x = new Foo("outer/static");
public Foo y = new Foo("outer");
public TimingOfInitialize() {
System.out.println("init TimingOfInitialize");
class Bar {
//error:
//public static Foo x = new Foo("outer/static");
public Foo y = new Foo("inner");
}
new Bar();
new Bar();
}
public static void main(String[] args) {
new TimingOfInitialize();
new TimingOfInitialize();
}
}
class Foo{
public Foo(String s){
System.out.println("initialized!" + s);
}
}
||<
出力結果
||
initialized!outer/static
initialized!outer
init TimingOfInitialize
initialized!inner
initialized!inner
initialized!outer
init TimingOfInitialize
initialized!inner
initialized!inner
||<
このようにJavaのstaticでないフィールドの「定義」はクラスの定義時には評価されない。クラスのインスタンスが作成された後で評価されるのでthisにそのクラス自体への参照が入っていてもアリ。
一方Python
|python|
>> class Foo(object):
def __init__(self, s):
print s, "initialized"
>> class Bar(object):
x = Foo()
outer initialized
||<
Pythonではクラスの定義文中に書かれている「Javaのフィールド定義によく似たもの」は即座に評価される。このxはJavaで言うところのstaticなフィールドで、Bar.xとしてアクセスされる。クラスについて話をしているんだからxはクラスオブジェクトに属するものであり、ここでインスタンスへの参照selfとか使えたら変、という考え方。
逆に言えばJavaのstaticでないフィールドの初期化は、Pythonでは__init__メソッドの中に書かれるべきものだから、そこでインスタンスへの参照が使えるのは自然。
というそれぞれの言語の違いに起因している気がした。
*1203435874*Perl角括弧でアレイのコピーになる @aという構文が出てきてコレは何なのかamachangに聞いたらアレイのコピーなんだって。 $b = @a;で@aがコピーされてそれへの参照が$bに入る。@$bと書いてデリファレンスしてやると同じ内容のアレイであることがわかる。 ||
C:\>perl -e "@a = (1,2,3); $b = @a; print $b" ARRAY(0x1001345c)
C:\>perl -e "@a = (1,2,3); $b = @a; print @$b" 123
||<
一方 $b = \@a;ならば参照のコピーなのでaを書き換えるとbも変わる。あれ、変わってない…。
||
C:\>perl -e "@a = (1,2,3); $b = \@a; $a->1 = 5; print @$b" 123
||<
-----
解答篇
@aは参照ではなくアレイの実体なので$a->1=5;ではなく$a1=5;でなければいけない。$aと@aは同じaという名前だけども別もの。$a->1=5;を実行したことで新たなアレイが作られその参照が$aに入っている。$aをデリファレンスした@$aと@aに別の物が入っていることが下のコードで観測できる。 ||
C:\>perl -e "@a = (1,2,3); $b = \@a; $a->1 = 5; print @$a;" 5
C:\>perl -e "@a = (1,2,3); $b = \@a; $a->1 = 5; print @a;" 123
||<
改めてきちんと$a1=5;と書くと$b = \@aは@aへのリファレンスが$bに入っているだけだけど、@aではコピーされているということがわかる。 ||
C:\>perl -e "@a = (1,2,3); $b = \@a; $a1=5; print @$b;" 153
C:\>perl -e "@a = (1,2,3); $b = @a; $a1=5; print @$b;" 123
||<
ちなみに$bはリファレンスなので$b->5とやってやらないといけない。$b5と書いてしまうと上とは逆に$bが指しているアレイとは別のアレイ@bが新たに作られてしまう。 ||
C:\>perl -e "@a = (1,2,3); $b = \@a; $b->1=5; print @a;" 153
C:\>perl -e "@a = (1,2,3); $b = \@a; $b1=5; print @a;" 123
C:\>perl -e "@a = (1,2,3); $b = \@a; @$b1=5; print @a;" 153
||<
まとめ:Perl初心者がPerlを学ぶ上でまず最初に覚えるべき命令はuse strictとuse warningsである。
||
C:\>perl -e "use strict; use warnings; my @a = (1,2,3); $b = \@a; $a->1 = 5; print @$b;" Name "main::a" used only once: possible typo at -e line 1.
123
||<
*1203437857*SEO
おっけ。SEO力の強いはてなダイアリーからh3タグでリンクを貼ったおかげか
が「nishio hirokazu」で検索したときには1位になるようになった。
むしろ検索結果の1ページ目が全部僕で占められている。
しかし残念ながら「hirokazu nishio」では9位だ。っていってもこっちも全部僕だけど。しかしGoogleは引用符でくくってなくても順番にだいぶ影響されるんだねぇ。こんなに検索結果が変わるとは思わなかったので残念。
僕のホームページに「状況によってはHirokazu Nishioと表記することもある」って書き足せば「hirokazu nishio」でもトップになるかな?
</body>
<comments>
<comment>
<username>yukoba</username>
<body>> 一人歩きしがちなので<br><br>まぁ、読者の少ない僕のブログなら、一人歩きしない気もするけどね(笑)<br><br>> 「重複していても *未来永劫* まとめてはいけない」<br><br>正確には、重複しているのは、うまく関数にしてまとめるべきだと思います。<br><br>論点は、if 文の作り方です。<br>たとえそれが正しくても、<br>・何をやっているかわからなくなるような、<br>・全ケースを網羅していることがわからなくなるような、<br>if文を書いてしまうと、どつぼにはまるという意味です。<br><br>まとめてしまった後、やっぱり、分けなきゃいけないことに気づいて、<br>分け始めるとグチャグチャになりやすいです。<br><br>もっと加筆すると、<br>「分割統治法で分けて考えないと理解できないような複雑な問題」<br>限定です。<br>分割統治法で分けたやり方に沿って if 文を構築すべきという主張です。<br><br>簡単な問題だと、ぶっちゃけ、てきと~に作っても何とかなっちゃうし(笑)<br>IDEによる、リファクタリングができる言語だと、本当に後付けできます。<br><br>あのブログに詳しく書いてないけど、クラスの分け方も同様だと思います。</body>
<timestamp>1203403432</timestamp>
</comment>
<comment>
<username>yukoba</username>
<timestamp>1203404908</timestamp>
</comment>
<comment>
<username>emo</username>
<body>public int a = this.a++;<br>で、0が代入されて、その後にaをインクリメントしているのに、<br>aが0のままなのに焦った。</body>
<timestamp>1203413471</timestamp>
</comment>
<comment>
<username>yukoba</username>
<body>なるほど!たしかに。単純な代入ではなくなっていますね。<br>逆に、なんのために、thisやsuperが使えるんだろう…<br>コンストラクタでの利用のみに限定し、変数宣言では使用禁止にすればいいのに。</body>
<timestamp>1203416871</timestamp>
</comment>
<comment>
<username>hayamiz</username>
<body>1つじゃなくて1袋の間違いじゃないですか?</body>
<timestamp>1203417738</timestamp>
</comment>
<comment>
<username>suztomo</username>
<body>HARIBOをなめきるのに17分なんてすごいですね! > <</body>
<timestamp>1203420885</timestamp>
</comment>
<comment>
<username>nishiohirokazu</username>
<body>>その後にaをインクリメントしているのに、aが0のままなのに焦った。<br><br>ホントだ、気づいてなかったけどこれも変だ</body>
<timestamp>1203434991</timestamp>
</comment>
<comment>
<username>ZIGOROu</username>
<body>use warningsですよ。本文間違ってる!</body>
<timestamp>1203436036</timestamp>
</comment>
<comment>
<username>nishiohirokazu</username>
<body>なおしました!</body>
<timestamp>1203437069</timestamp>
</comment>
<comment>
<username>SiroKuro</username>
<timestamp>1203437553</timestamp>
</comment>
<comment>
<username>nishiohirokazu</username>
<body>つまり、this.aの初期化のタイミングでは<br>- this.aが0で初期化される<br>- this.a++が実行され、this.aが1になる。この式は0を返す。<br>- this,a = 0が実行されthis.aが0に戻る<br>という現象が起きているわけですね。</body>
<timestamp>1203473423</timestamp>
</comment>
<comment>
<username>emo</username>
<body>なるほど<br>問題はこのようなコーディングがしたくなるシチュエーションが<br>どれほどあるかなんだけど。<br>あるんだろうか。。<br>私は思いつかない。</body>
<timestamp>1203477852</timestamp>
</comment>
</comments>