読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

日本語マニュアル更新

Maximaの日本語マニュアルを5.37.2に更新しました。
(10月11日に更新したのですが、1箇所訳せなかった部分がようやく訳せたので告知させていただきます。)

一度引退したはずなのですが、変更箇所が少ない状況が続いていますので、まあやっちゃうかという感じです^^;

underscore形式の名前をCamelCaseに変換する

Atomのfind-and-replaceは正規表現が使えますが、JavaScript仕様なので、置換文字に\u(小文字を大文字に変える)などのメタ文字が使えません。
JavaScriptのreplaceは置換文字列引数に関数を与えることができ、それでなんでも変換できるようになっていますが、find-and-replaceには文字列しか渡せないので、表題である「underscore形式の名前をCamelCaseに変換する」ことができません。

なので、init.coffeeに簡単なコマンドを追加しました。

atom.commands.add 'atom-text-editor', 'my-tools:underscore-to-camelcase', ->
  return unless editor = atom.workspace.getActiveTextEditor()

  editor.buffer.replace /_[a-z]/, (str) ->
    str[1].toUpperCase()

これで、コマンドパレット(shift-cmd-p)からmy-tools:underscore-to-camelcaseを実行すれば、名前を変換してくれます。

逆変換は本来もっとややこしい気もしますが、あまりこだわらない単純な実装なら、以下のような感じ。

atom.commands.add 'atom-text-editor', 'my-tools:camelcase-to-underscore', ->
  return unless editor = atom.workspace.getActiveTextEditor()

  editor.buffer.replace /[a-z][A-Z]/, (str) ->
    str[0] + '_' + str[1].toLowerCase()

Collection Typeを使う重い計算にSwiftを使うにはまだ時期が早い?

アルゴリズムに専念できる「高級」言語でコンピュータ囲碁をやってみたいと思い、Swiftを選択してみました。
原始モンテカルロ碁を実装してみて、結論として、残念ながらSwift 2ではまだこういう計算は大変という結論を得ました。

以下、ボトルネックとなったところ。

// reference : Mr. Yamashita's sample code in lectures in Dentsu University

let dir4 = [1, WIDTH, -1, -WIDTH]

func count_liberty_sub(tz: Int, color: Int, inout liberty: Int, inout stone: Int) {
    ...
    for dir in dir4 {
        ....
        if board[z] == color {
            count_liberty_sub(z, color: color, liberty: &liberty, stone: &stone)
        }
    }
}

このコードが重いのです。dir4はグローバルな定数ですが、関数count_liberty_subで使う時、Swiftは礼儀正しく、swift_bridgeObjectRetainを実行し、その中で_swift_retain_を実行します。
そして関数が戻る時には_swift_release_を実行。
このretainとreleaseがそれぞれ1-2msかかるので、他の処理にほとんど時間がかからなくても重い処理になります。

(試しにdir4に配列リテラルを直接描いてみたら、配列リテラルの生成とリリースが都度発生して悪化しました。)

グローバルな定数配列でARCをしても仕方ないと思うのですが、どういうものなのでしょう?

ちなみに、Optimization LevelはFast, Whole Module Optimizationです。

Swiftベンチマークでいい数字出しているようですが、全体に、ArrayやSetなどCollection Typeを使うとまだスクリプト言語並みに重いという印象です。

cloneメソッド

最近、Swiftを始めました。Swiftはいいとこ取りの言語で、どこかで見た良さげな言語仕様が採用されているので書きやすいです。
でも、インスタンスをコピーするcloneメソッドで苦労しました。

事実上finalのクラスに単にcloneメソッドを実装する分には何の問題もないのですが、スーパークラスになることを前提に、しかもインスタンス変数を増やさないサブクラスでも動作するようなcloneメソッドの定義は大変でした。

以下が苦労した結果の集大成です。

class SuperClass {
    var value: SomeValueType // for simplicity of sample

    init() {
        self.value = SomeValueType()
    }
    
    required init(clone: SuperClass) {
        self.value = clone.value
    }

    func clone() -> Self {
        return self.dynamicType.init(clone: self)
    }
}

インスタンス変数はValue Typeとしました。もしReference Typeを使いたいなら、init(clone:)がReference Typeのcloneを使うように変更する必要があるでしょう。

重要なポイントは以下の2点です。
#コピーの実装部分にinitを使うこと
#コピーコンストラクタにrequiredをつけること
#cloneメソッドの戻り値の型にSelfを指定すること

これで、インスタンス変数を増やさないサブクラスは、何もしなくてもcloneメソッドが使えます。
インスタンス変数を増やした場合には、もちろん、init(clone:)をoverrideしてください。(overrideというキーワードは使わず、requiredでオーバーライドします)

cloneをcomputed propertyにしたかったのですが、Swift 2では型としてSelfを指定できるのは戻り値だけなのでできないようです。

Bootstrapのドロップダウンメニューのhover効果をiOS Safariで改善する

Bootstrap(3.3.5)は様々な場所でCSSのhoverを利用しています。
残念ながらiOS Safariではhoverに該当する状態がなく、ドロップダウンメニューでどれをタッチしたかわかりにくいなどという問題が発生します。

検索すると、hover対応の凝ったJavaScriptコードがたくさん見つかりますが、Bootstrapに限ればそう大層なことをしなくても改善できます。
例えば、Bootstrapのドロップダウンメニューはhoverとfocusに同じ設定がされているため、以下の5行でOK。

$(document).ready(function() {
    $('.dropdown-menu>li>a').on('touchstart', function() {
        $(this).focus();
    });
});

これだけ。touchstartと同時にfocusさせると、hoverと同じ色になってくれるので、どのメニューをタッチしたかがわかるようになります。

TAPi18nのページロード時の振る舞いの改善

Meteor + Iron Routerの国際化にiron-router-i18nとTAPi18nを使っています。
TAPi18nはなぜかデフォルト言語として英語を読み込み表示、その後setLangaugeで言語が設定されるとその言語に切り替えると仕組みになっています。
なので、ネットワーク遅延の目立つ環境では、最初英語版のページが表示され、その後所望の言語に切り替わります。ユーザーの立場から見ると国際化とはわかっても途中でページをすり替えているように気分はあまり良くないですね。

そこで、英語の状態のページの表示を抑制するコードを書きました。
まずbodyをデフォルトで非表示にします。

<body style="visibility: hidden;">
{{> Router}}
</body>

クライアント側の言語設定とbodyを表示にするコードを追加します。

# client

I18NConf.onLanguageChange (oldLang, newLang) ->
    TAPi18n.setLanguage(newLang).done ->
        document.body.style.visibility = 'visible'
        return
    return

やっぱりちらりと英語が見えることがない方が気持ちがいいですね。