コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2008年2月7日 >>> 2008年1月29日
link もっと後

2008年2月7日

Genericsとcloneメソッド

このキーワードでピンと来た方はこの日記を読む必要はないと思います。

Genericsなクラスにcloneメソッドを作ろうとしてはまりました。以下のようなコードを書いたわけです。

Genericsなクラスでディープコピー(MyVector.java)

class MyVector<T extends Cloneable> implements Cloneable {
    T[] items;
    
    public Object clone() {
        MyVector<T> copy = new MyVector<T>();
        
        for (int i = 0; i < items.length; i++) {
            copy.items[i] = (T)(items[i].clone()); //error!!
        }
        return copy;
    }
}

Cloneableを継承する型だと宣言したところでCloneableインタフェースにはclone() の定義がありません。コンパイラはこのコードを見てもTがpublicメソッドのclone() を持っているのか、いないのかコンパイル時に判断できません。

従ってこのコードを実行すると基底クラスのObjectクラスのclone() メソッド(privateメソッド)が呼ばれる可能性があります。そのためコンパイラは「(Objectの)clone() はpublicじゃないから呼べません」とエラーを出すのです。

clone() を呼ばずに、以下のようなコードに直せばコンパイルが通ります。しかしこのコードで生成されるTのコピーはあくまでも「シャローコピー」ですから、Tがシャローコピーでコピーしきれない要素を持っていたときに破綻します。


copy.add(get(i)); //OK

配列の要素まで「ディープコピー」をするには、Tにclone() 関数の定義を強制させる必要があります。これにNewCloneableとでも名前を付けますと、以下のようになります。

Cloneを強制する(MyVector2.java)

public interface NewCloneable extends Cloneable {
    public Object clone();
}

class MyVector2<T extends NewCloneable> implements Cloneable {
    T[] items;
    
    public Object clone() {
        MyVector2<T> copy = new MyVector2<T>();
        
        for (int i = 0; i < items.length; i++) {
            copy.items[i] = (T)(items[i].clone()); //OK
        }
        return copy;
    }
}

新しく作ったMyVector2クラスは「ディープコピー」ができるようになりました。しかしこのクラスは全く使い物になりません。なぜならNewCloneableを継承するクラスは標準クラスライブラリに存在しないからです。つまり何を言っているのかというと、


MyVector<Integer> v1;  //OK
MyVector2<Integer> v2; //error!!

MyVectorと同じ乗りでMyVector2を使おうとすると「IntegerはNewCloneableを実装してないからダメ」と怒られます。せっかくのGenericsなのに自分で作ったクラスしかぶち込めないんじゃ、ちょっとあんまりですよね。

それならと、Integerを継承してNewCloneableを実装したクラスNewIntegerを定義しよう!と思ってもIntegerはfinal宣言されていて継承できません。MyVector2はますます役立たずです。

結局はシャローコピーで我慢せよってことですかね。もしくはclone() なんか実装すんじゃねーよってことでしょうか…。

編集者:すずき(2008/02/15 01:09)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年2月6日

PukiWikiのrelatedプラグインの謎

目次: 自宅サーバー

PukiWiki 1.4.7に関連するページへのリンクを表示するrelatedというプラグインがあります。リンクには二種類あって、

  • 対象となるページにあるリンク(以降、順リンク)
  • 対象となるページをリンクしたページへのリンク(以降、逆リンク)

が表示されるようになっています。

PukiWikiの編集時にブロック型プラグイン形式 #relatedか、index.php?plugin=related&page=PageNameのように(便宜的に直起動と呼ぶ)してpluginを呼び出すことで上記の機能が発動します。

どちらの起動方法でも機能は同じ……そんなふうに考えていた時期が俺にもありました。
バキネタはさておき、relatedプラグインってば直で起動するとブロック型とは別の処理が走ってしまいます。そのせいで順リンクが出ません。なんだこれ。

PukiWikiなんてそこら中で使われてるし、relatedの妙な動きにも誰か気づいていそうなもんですが…、そもそもどちらの動きが正しいんでしょう?それによっては以下のエントリが丸々無駄になる可能性があったりなかったり。

backlinksプラグイン

PukiWikiで「ひらメソッド」をやってみると、ある関数が誰を呼ぶか?という一覧の他に、ある関数が誰から呼ばれ得るか?ってのも知りたくなりませんか?

その手の情報は手動で管理すると死ねるので、逆リンクの一覧をページに埋め込むってのが欲しかったわけです。しかしながら #relatedでは、先述したように順リンクが混ざってうまくないです。

relatedを直すとあちこちに影響が出そうなので、今のところは、以下の図のような対象ページの逆リンクだけをすっぱ抜いてくるbacklinksプラグインを追加して凌いでいます。

backlinks.inc.php

<?php
// PukiWiki - Yet another WikiWikiWeb clone
// Backlinks plugin: Show backlinks for the page

function plugin_backlinks_convert()
{
	global $vars;

	return make_backlinks($vars['page'], 'p');
}

function make_backlinks($page, $tag = '')
{
	global $script, $vars, $rule_related_str, $related_str;
	global $_ul_left_margin, $_ul_margin, $_list_pad_str;

	$links = links_get_related_db($vars['page']);

	if ($tag) {
		ksort($links);
	} else {
		arsort($links);
	}

	$_links = array();
	foreach ($links as $page=>$lastmod) {
		if (check_non_list($page)) continue;

		$r_page   = rawurlencode($page);
		$s_page   = htmlspecialchars($page);
		$passage  = get_passage($lastmod);
		$_links[] = $tag ?
			'<a href="' . $script . '?' . $r_page . '" title="' .
			$s_page . ' ' . $passage . '">' . $s_page . '</a>' :
			'<a href="' . $script . '?' . $r_page . '">' .
			$s_page . '</a>' . $passage;
	}
	if (empty($_links)) return ''; // Nothing

	if ($tag == 'p') { // From the line-head
		$margin = $_ul_left_margin + $_ul_margin;
		$style  = sprintf($_list_pad_str, 1, $margin, $margin);
		$retval =  "\n" . '<ul' . $style . '>' . "\n" .
			'<li>' . join($rule_related_str, $_links) . '</li>' . "\n" .
			'</ul>' . "\n";
	} else if ($tag) {
		$retval = join($rule_related_str, $_links);
	} else {
		$retval = join($related_str, $_links);
	}

	return $retval;
}
?>

PukiWikiのpluginディレクトリにbacklinks.inc.phpという名前で置いて、PukiWikiでページ編集するときに #backlinksと書けば動作するはずです。PukiWikiのコード(make_related関数)をそのままパクッてるんで、ライセンスはGPLです。こんなんで良ければご自由にどうぞ。

編集者:すずき(2024/01/13 17:13)

コメント一覧

  • IKeJIさん(2008/02/08 10:58)
    related は他にもバグがあるんですが、Pukiwikiは死んでるんですかね?
    http://pukiwiki.sourceforge.jp/dev/?BugTrack%2F735
  • すずきさん(2008/02/08 18:22)
    >IKeJI さん
    PukiWiki は最近バージョンアップしてないようですし、開発が停滞しているのかも知れないですねえ。
    >他のバグ
    ありゃーこれはかなりだめな挙動ですね。直さないのかな。

    #backlinks は大丈夫かな…?ダメだったら直すのメンドクサイなあ。
open/close この記事にコメントする



2008年2月5日

最近のほっかいろ

会社の挨拶運動に参加しました。寒空の下30分間、会社の入り口で「おはようございまーす」を連呼しました。

寒さを考慮してほっかいろを配ってくれたので早速使ってみたのですが、最近の製品は発熱量が少ないみたいです。かいろが暖かくなるどころか逆に寒さに負けて冷たくなってくる始末。低温火傷に配慮したのかなあ?それにしてはやりすぎだよなあ?

編集者:すずき(2008/02/08 03:01)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年2月4日

キング・オブ・クソゲー

ちょっと前にニコニコ動画で大流行していた「チーターマン」という伝説級のクソゲーがあるんですが、これを越える超絶クソゲーがあります。

「未来神話ジャーヴァス」というファミコンのゲームなのですが、アクションRPGにも関わらず、説明なくゲームが始まって当然、てな作り方です。ターゲット層と思われる小学生に理解させる気ゼロです。

バッテリーバックアップカセット、クエストシステム、城攻めなどの斬新な要素(当時)も見られます。しかし基本が即死というバランスの悪さ、説明不足すぎて理解不能なクエストなどマイナス点が多すぎです。これは常人にはクリア不可能だと思われます。

ニコニコにクリアムービー(かなり省略されてます)が載ってたので、暇で仕方ない人は探してみてください。見ていても何してるのか全然わからんのが難点だけど…。

編集者:すずき(2008/02/08 02:55)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年2月3日

らららープレイステーション

今日は飲み物を買いに行ったりしたくらいなので、昨日の晩〜深夜にかけて、友達とゲームしてた話でも。

PS3のありあまるパワーを生かして、ハイビジョン画質(1080p出力)をでかい画面(50インチのプラズマ)に繋いで、ガンダム無双やってました。ポリゴンのアラが見えてしまうくらい、綺麗だなあ。

Wiiiiiii!!!!!!!!

Wiiでパワプロもやりました。リモコンを振って投げる/打つってのが楽しいです。最初はシンプルすぎる操作を見て、プレイヤーを馬鹿にしてると思ったんですが、やってみると逆にシンプルさが楽しいです。

ただ、PS3やった後にWiiの絵をみると、ぼやけているというかなんというか…。やるなら逆の順番にしたほうが良さそう。

編集者:すずき(2008/02/08 02:43)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年2月2日

スーキヤーキ

友人の誘いに乗って、京都の三嶋亭にすき焼きを食べに行きました。店の雰囲気に対して、ジーパン+トレーナーという僕らの服装が激しく場違いでした。あやうく周囲の視線で針のむしろになるところでした。個室で良かったと思います。

一食で一ヶ月の食費の半分くらいが吹っ飛びました。しかし…、うまかった…!

ジンジャー

食事を食べた後は京都の町をぶらぶら。京都のコンビニはみんな地味な色にしていて面白いです。街並みとの調和ってやつでしょうか。

近くの八坂神社にお参りしました。門の修復工事が終わっていたので、写真を撮りました。柱の朱が鮮やかです。今はまだ直したてで綺麗すぎるきらいがありますけどしばらくしたら良い味が出るでしょう。


八坂神社の正門前

神社にお参りしてお土産買った後は、パフェを食いました。男五人でな…、なんか最近こんなのばっかりだw

編集者:すずき(2008/02/08 02:34)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年2月1日

そりゃないぜ

会社からの帰り道、電車の到着時刻を知らせる電光掲示板を見るとなんかおかしい。先に来るはずの8分が、16分の電車の下に表示されています。普通は到着時刻順に並ぶはずです。


時刻順と逆に表示されている

そのまましばらく電光掲示板を見ていると、JR西日本恒例の赤い文字(電車の遅れ時間を示す)が。またですか、もう勘弁してください。


どんどん遅れが増えていく

ああ、これはだめだって思ってたら「8分の普通電車は16分より後になる」ってアナウンスが入りました。電光掲示板の順番が入れ替わってる=先行(8分の電車)は来ませんよ、って予告なんですねっ…て、わかりづらいよ。

最終的には10分遅れになって、時間順で正しい順番になりました。結局ホームで20分も待っちゃったYO!遅れの原因は、小動物を跳ね飛ばしたせいらしいです。へぇー。

編集者:すずき(2008/02/08 02:23)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2008年1月31日

long longの罠

目次: C言語とlibc

突然printfの動きがおかしくなって、引数で与えた数値を表示したりしなかったりするようになりました。

で、調べてみるとこーんなプログラムになってたわけです。


#include <stdio.h>

int main(int argc, char *argv[])
{
  long long int a;
  int b, c;

  a = 0x1234567887654321LL;
  b = 200;
  c = 300;
  printf("a:%d, %s, b:%d, c:%d \n", a, "strings", b, c);

  return 0;
}

実行してみると

$ gcc a.c
$ ./a.out
Segmentation fault

見事に落ちました。

このプログラムのまずいところは変数aは8バイト(long long int型)あるのに、printfには %d書式(signed int型の指定)と指示しているため、printf側が4バイトしか見ない、ってところです。残った4バイトは次の %s指令のデータと見なされて、その結果変なアドレスを見に行ってプロセスが死にます。

なので、この場合は %dじゃなくて %lldと書いてlong long signed int型であることを指定すべきです。正しく動いたときの結果はこんな感じ。

$ ./a.out
a:1311768467139281697, strings, b:200, c:300

整数だからといってなんでもかんでも %dにしちゃだめですよ、って教訓ですな。

$ gcc --version
gcc (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc -Wall a.c
a.c: In function 'main':
a.c:12: warning: format '%d' expects type 'int', but argument 2 has type 'long long int'

ちなみにgccなら -Wallオプションを指定すれば、printfの書式指定が間違っていたときに教えてくれます。

the Typedef Hell!!

もちろん好きこのんでこんな状態を作ったわけではありませんので、お間違いなく…。

この問題に出会うきっかけとなったプログラムは、言うなれば「typedef地獄」でしょうか。ぱっと見ても、整数なのか浮動小数点数なのか、はたまた構造体なのか…型が全くわかりません。何よりひどいのはtypedefが連鎖しまくっていることでしょうか。

例えばAライブラリのA_TypeがBライブラリのB_Typeのエイリアスだったとして、そのB_TypeがさらにCライブラリのC_Typeのエイリアスで、それがさらにDの…というように、ひねりのないtypedefが延々と続きます。

そのくせ最後まで辿ってみると無条件でtypedef int X_Type;(単なるint)とかいうオチが多いので、ウザいことこの上ない。

やがて調べるのが面倒くさくなって、どうせlongかintだろって思ってなめてたら、long long intのエイリアスがいくつか混ざっていて、警告オプション -Wallもご丁寧に抹消されており、上記の問題にはまったわけです。

C言語において、ダメなマクロの話は良く聞きますが、ダメなtypedefの使い方はそうそうないと思う。

編集者:すずき(2023/02/04 20:26)

コメント一覧

  • hdkさん(2008/02/02 01:02)
    型って難しいですね。昔は 16 ビットをこえる整数を扱うのに long int を使っていましたが、今は環境によっては 64 ビットになってしまいます。typedef を使うと、あとから変えるのは簡単になりますが、それはそれで読みづらい。printf みたいな変な関数が存在する C の仕様が古すぎるんでしょうか。(C++ の cout ならこの手のトラブルは起きないのかも...)
    # ちなみに x86 の 64 ビット環境なら上のプログラムはちゃんと動いてしまいますw
  • すずきさん(2008/02/02 03:17)
    >hdkさん
    C のうまくないところは
    ・環境により int の大きさが変わる
    ・printf のような可変引数を取る関数がある
    ってところでしょうか。
    >typedef
    3連鎖以内に抑えていただければ幸せだったなー、と…(泣
    >64ビット環境
    64ビットなら問題ないっす。32ビットを想定ってのを書き忘れました。
    # そしてまた 64 -> 128 ビットの交代時に C 言語(きっと生き残っている)は同じ問題を起こすわけか…。
open/close この記事にコメントする



2008年1月30日

食べるな、と来たか

大好きな蒟蒻畑をダイエーで3袋くらい買ってきてもさもさ食ってたら、一瞬でなくなりました。しかも食べ過ぎて具合悪くなってきたし…。

それはさておき、蒟蒻畑の袋に「高齢者と子供は食べないで」というイラストが入っていることに気づきました。以前は裏側に「気をつけて食べて」とか「スプーンで食べて」という注意書きがあっただけだった気がします。


蒟蒻畑の袋

袋の表にしっかり描いてありますね。右下のマークの部分を拡大すると、以下のような具合です。


蒟蒻畑の袋、拡大図

食べるな、とはっきり描いてあります。喉に詰まらせる事故が起きる度にこの手の警告は厳しくなりますが、ついに注意や警告ではなくて禁止になってしまったようです。事故が起きまくる交差点が一時停止 -> 信号 -> 歩車分離へと進化する(?)のと似たような物か…。

編集者:すずき(2008/01/31 00:08)

コメント一覧

  • mamaさん(2008/02/01 09:55)
    歩車分離の次は・・・
    通行止め・・ってことはないですよね。www
  • すずきさん(2008/02/02 03:36)
    最近の食品問題を見ると、不祥事を起こして販売取りやめってパターンも珍しくないです。起きて欲しくはないですが、次は「通行止め」ではなく「廃線」でしょうね。
    マンナンライフにはこれからも良い蒟蒻畑を作ってもらいたいです。いっぱい買うぜー。
open/close この記事にコメントする



2008年1月29日

3倍速い

Javaでプログラムしていたら妙な現象に気づきました。

  • Component.createImageかComponent.createVolatileImageで大きめのバッファ(少なくとも800x600くらい?)を作ります。
  • バッファに何か(ここではfillRect)描きます。
  • バッファの内容をComponentにdrawImageしてコピーします。
  • 特定の待ち時間(11ms〜19ms)を指定したThread.sleepを呼び出します。

以上の処理を行うループを回していると、PCの時計が3倍くらいの速さでどんどん進んでしまいます。バッファに何も描かずにdrawImageするであるとか、20ms以上の時間をsleepに指定した場合には、問題ないようです。

バッファに描いてdrawImageしてsleepを呼んで待つ、というパターンはゲームでありがちな処理だけに困ってしまいます。何が悪いのかさっぱりわからない。Javaとその内部に詳しい人が居たら、何が起きてるのか教えて欲しいところです。

それともなんだ、地球のためにCPUパワーを食うBlitではなくFlipにしなさいっておぼしめしなのか…?

検証コード

検証に使ったコードは以下の通りです。

TestClockSkew.java

import java.applet.*;
import java.awt.*;

public class TestClockSkew extends Applet implements Runnable {
    Image i;

    public void init() {
        i = this.createImage(800, 600);
        
        Thread t = new Thread(this);
        t.start();
    }
    
    public void run() {
        while (true) {
            Graphics g = i.getGraphics();
            g.setColor(new Color(0, 0, 0));
            g.fillRect(0, 0, 500, 500);
            g.dispose();
            
            this.getGraphics().drawImage(i, 0, 0, null);
            
            try {
                Thread.sleep(11);
            } catch (InterruptedException e) {
            }
        }
    }
}

当初は実際に動作するアプレットを貼りつける予定でした。しかし実行したところで、黒い画面が出るだけで何も面白くないうえに、もし皆さんのマシンの時計が狂ったりしたら大迷惑なのでやめました。

編集者:すずき(2008/02/15 01:07)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2008年2月7日 >>> 2008年1月29日
link もっと後

管理用メニュー

link 記事を新規作成

<2008>
<<<02>>>
-----12
3456789
10111213141516
17181920212223
242526272829-

最近のコメント5件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」

最近の記事3件

  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月19日
    すずき (03/20 02:52)
    「[モジュラージャックの規格] 古くは電話線で、今だとEthernetで良く見かけるモジュラージャックというコネクタとレセプタク...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 03/26 03:20