あんまり怖くないと思いたい null

多くの開発者にとって、null は忌避すべきものだ。
万が一、null に*さわってしまった*ら、あなたは突如発生した例外により、ヨルダン辺りまで吹き飛ばされるだろう。
あと、えーっと、オフィスの天井も失くなってしまう。
null の影響で行方不明になったり、命を失ってしまうえんじにゃーは毎年 500 万人を超える*1

このため、null をなんとかしようと様々な手法が開発されてきた*2

つーか、null を最初にだいにゅーさせなくすればいいんじゃね?

最初にどこかの変数に null をだいにゅーしておくと、長ーいコードの途中で長い時間をかけて膨らみ、いつしか破裂し、あなたを吹き飛ばす。

これはある。
っていうか、十中八九、これでぬるり*3がでてるんじゃないかと私の中では専らの話題である。

あと、クソ長いコードのせいで、どの時点でどの変数が null なんだっけ? とか考えるのすっごいめんどい。

Swift)なんかは言語仕様的にできなくしてるみたい。

あんまりないかもしれないけど、メソッドの最初の方に変数宣言をまとめるのやめようぜ?
変数宣言は必要な時に限ってその場で宣言しようぜ!!

( ◠‿◠ ) 変数宣言したけど、その時点ではだいにゅーするもん無いから null 入れとくわーwwwwww

とか、あかんやつだから!!!

null なんて無い方が良いよね………(過激派)

╰( ´◔ ω ◔ `)╯ まあ、無いなら無い方が嬉しいけどな

頭の良い null ならいいんじゃないかな

╰( ´◔ ω ◔ `)╯ わりぃ、あんまり思いつかなかったわ

public static NullExtensions {
    public bool IsNull<_Type>(this _Type self) where _Type : class {
        return self == null;
    }
}

ʕ•͡ω•ʔ Option か Maybe を返して、何か呼び出す時はその中で行うとか?

あとは……

int.Parse() じゃなくて、int.TryParse() 使おうなって五億回くらい言ってる。

*1:適当な数値であり、事実に基づいて書かれているわけではありません

*2:多分

*3:NullReferenceException のこと

ファイルのサイズを取得するには?

Strongtalk のソースコードを読んでいたところ、このような記述を見つけた:

void Bootstrap::openFile() {
    stream_ = fopen( file_name_, "rb" );
    if ( stream_ == NULL ) {
        has_error_ = true;
        lprintf( "\nCould not open file (%s) for reading!\n", file_name_ );
        exit( -1 );
    }

    int no = _fileno( stream_ );

    file_size_ = _filelength( no );
}

file_name_fopen 関数で開き、_fileno 関数で inode 番号*1を取得し、 それに対応するファイルサイズを _filelength 関数によって取得するのだが、うにっくす環境には _fileno_filelength が無いのである。

C言語でのファイルサイズ取得方法 を見ると、fseekSEEK_END を使うのは脆弱なので、 fstat を使えと書いてある。

ということで、書いてみた:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

inline off_t get_file_size(const char* filename) {
    struct stat file_status;

    stat( filename, &file_status );

    return file_status.st_size;
}

動かせるようにしたものがこっちに置いてある。

VC++ では stat眷属が 12 種類もあることは見なかったことにしておく。
窓に!窓に!

ちなみに githubStrongtalkコードでは該当箇所はコメントアウトされていた。

*1:と言って良いんだろうか?

カレー・ブルストの作り方

www.adventar.org

  1. ボイルしたソーセージ(ブルストとも呼ばれる。なるべく太いものが望ましい)を食べやすい大きさに切る。
  2. ケチャップを親の敵のようにかける。
  3. 死ぬほどカレー粉をまぶす。

╰( ´◔ ω ◔ `)╯ Windows でも Perl6 が使えるように rakudo を clone してビルドしてみたが、ビルドできなかった……

╰( ´◔ ω ◔ `)╯ その前にインストーラーを使ってインストールしておいたんだけどな

雨に唄えばおじさんと揚げ玉ビーチ

www.adventar.org

╰( ´◔ ω ◔ `)╯ またまた Swiff の話だ

╰( ´◔ ω ◔ `)╯ 多分な

換気扇の空、オリーブオイルの海、揚げ玉の海岸。
雨に唄えばおじさんは自分が厄介な場所に来てしまったことを悟った。

ということで、以下のコードはコンパイルエラーになる(はず):

let hoge : Nil  = nil;         // Nil のみの型を持つ変数の宣言はコンパイルエラーになる。

let piyo : int? = nil;         // Nil 許容型の変数に nil を初期値として設定するとコンパイルエラーになる。

let fuga : int  = nil;         // 整数型の変数に nil を初期値として設定するとコンパイルエラーになる。

hoge の方は、やっても意味がない宣言だと思う。nil しか設定できないし……。

piyo の方は、null 排斥運動におけるコンパイルエラー。
多くの場合、最初に null が入っているから NullReferenceException が送出されるので、 null を初期値として設定しないようにすれば多くの場合 NullReferencException を退けられるだろうという考えらしい。
Wikipedia では「安全性のために」としか書いてないけど。

fuga の場合はそりゃそーだよなって感じ。int 型の変数に nil は設定できない。

でも、こっちはどうだろう:

let hage = getHage();

getHage() がこうなっていると:

def getHage() : int? {
    if true {
        return nil;
    }
    42;
}

hage には nil が設定される。
こういう場合は、「nil しか返ってこなさそうですよ」って Warning を表示した方が良いんだろうか?
っていうか、こういう場合、Visual Studio*1 では到達不可能なコードなんちゃらあるって言われるよな………。

こういう場合は、やっぱりなんともならないよなぁ:

let hyoga = int.parse( "X" );

まあ、関数の戻り値の nil はいいことにしようっていうか、リテラルとしての nil を設定するのがダメってことなんだもんね。

あと、複合型の Nil 許容型とジェネリックな Null 許容型が 2 つあるとよくない気がしなくもない。

*1:っていうか csc とか

カーネルおじさんによる美味しくできるニワトリ料理パターン

www.adventar.org

╰( ´◔ ω ◔ `)╯ 毎回記事本体じゃなくて、ナンセンス釣りタイトルを考えるのに時間を費やしてる気がしなくもない

今朝は Swiff の型について考えたような気がする。
自分の中では Swiff も Uva も文法的なところが違うだけのようになってきたので、どんどこどーん!

Swiff は Swift や Rust、Kotlin をインスペクトしているので、let は変数宣言で、val は定数宣言になってる。

すごく簡単に書くとこんな感じ:

("let" | "val") <識別子> [":" <型ヒンティング>] "=" <値> ";"

val だった場合は、<値> 必須だとか色々あるけど、こんな風に変数または定数を定義する。
例を示すとこんな感じ:

let hoge = 42;
let piyo : string = "Cunky bacon!!";

val TeddyBearFee = 6000;

上記の例で val で宣言された識別子、ええっと、定数が UpperCamelCase で表記されていることに気がついた人もいるかもしれない。
そして、定数が UpperCamelCase でないとコンパイラがブーブー言うだろうと思った人は安心していい。
そんなことはない。

Wikipedia の Swift の記事において var*1 で宣言された識別子は定数と呼ばれていた。
でも、そうじゃなくて、変更できない変数あるいは束縛と呼ぶべきだったのだ。
典型的な関数型プログラミングの考え方では、私たちが変数と呼ばれているものは実は値に名前が書かれた札が紐で結ばれているだけで、 それは分かちがたく結びついているので変更できない。
このことを不変更性を持つと呼ぼう。
札から下がった紐が果てしなくこんがらがって絶対に解くことはできないのだ。

とはいえ、実用的なプログラミング言語にそのようなパズルみたいな難解な代物を持ち込むべきではないと今でも思っている人たちも大勢いるわけで、 彼らにも配慮してやらなければならない。

私としては不変更性はすごく重要だと思っているので Uva では普通に宣言した変数は不変更性を持つようになっている。
どうしても変更可能な変数を宣言したい場合は variable アノテーションをつければいい。

Swiff はカジュアルな言語を志向しているので、型ヒンティングは :(コロン)で識別子の後ろに付けることになる。
もちろん、そんな面倒なことをしなくても、型推論によってある程度変数の型はコンパイル時に決定される。
Uva でも型推論で同じように変数の型は決定されるけど、そうしたい旨をコンパイラに伝えないといけない。
それが auto キーワードだ。
Uva は Swiff の後置に対して前置タイプなので、型ヒンティングを必ず付ける必要が生じる*2
でも、Uva には静的型付き言語の顔をしてほしかったため、C++ から auto を取ってきた。

(。ŏ﹏ŏ) こうしてみると、Uva と Swiff って性格が違うんだね

╰( ´◔ ω ◔ `)╯ そうだな

更に、関数定義でも fun ではなく、def を採用した。

def is_nil(x : T?) : bool {
    match x {
        is T    => true,
        is Nil  => false
    }
}

あと、match 式 (・∀・)イイ!!
という感じだったので、switch は無し。

return もあるけど、基本的には最後の値が返されるという感じ。
後置 if とか 後置 unlesswhileuntil もあるよ。

let x = if x < Screen.width then x else Screen.width;   // :? タイプの if 式

let y = if y < Screen.height {
    y
} else {
    Screen.height
};                              // if っぽい if 式

if は式だし、then 節はかっこつけなくてもいいんじゃないかとかとかとか…………。

*1:Swift ではそれは val でなくて let なのだ

*2:variable で代用することもできるけど、不変更性を持つ変数の場合は? const を使いたくなかった

Uva をはじめようかなー

www.adventar.org

エントリーポイント

Uva は決まったエントリーポイントを持たない言語です。
例えば、クラスの外においては Java は一切の文あるいは式(クラス・インターフェイス定義、import 文、package 文を除く)を書くことが許されていませんが、 Uva では許されています。
なので、println( "Hello, World!" );main() の外に書いても構いません。

shared のこと

shared というのは一見キーワードのように見えますが、実のところアノテーションの 1 つです。
shared が付いた関数や変数、クラスなどはこのソースコードの外からでも見えるようになります。
つまり、可視性を司るアノテーションです。

ループ

Uva にはループは for-inwhileuntil の 3 つがあります。
for-in は以下のような、C# でいう foreach の形をもつ for 文です。

for ( auto i in 1..5 ) {
    for ( auto j in 1..j ) {
        print( "*" );
    }
    println();
}

標準出力への出力

標準出力に出力する方法の 1 つとして、println() があります。
これは、何らかの値を出力し、最後に改行を出力するという関数です。

ちなみに、最後に改行を出力しない同じような関数として print() があります。

print()println() はそれぞれ、process.stdout.print()process.stdout.println()エイリアスです。

process オブジェクト

process はビルトインの現在のプロセスを表すオブジェクトです。

    variable String? input = process.readLine();

null 許容型

process.readLine() の戻り値は String? です(おそらく)。
String? の後ろの方の ?null が入っているかもしれない String 型という意味です。
String? を別の表記(複合型表記)で表すと String|Null です。

Null 型の唯 1 つのオブジェクトが null です。

    if ( exists input ) {
        String[] tokens = input.split();
        int?[] numbers   = tokens.map( int.parse );
    }

例えば int.parse() は整数値にパースできない文字列が渡された場合、null を返します。
このようなメソッドないしは関数の戻り値型は ? 付きです。

is

ある型 Tnull 許容型 T? の値が null かどうかを確かめる 1 つの方法が is 式を使うことです。
is 式は右オペランドの値が左オペランドの型あるいは左オペランドの型を継承した型である場合、真を返します。

if-exists ガード句

もう 1 つの方法が if-exists ガード句を使う方法です。

Hoge? hoge = getHogeOrNull();

if ( exists hoge ) {
    // このブロックでは hoge は Hoge 型であることが明確になる。
    println( "it's Hoge" );
} else {
    // このブロックでは hoge が null であることが確実。
    println( "it's null" );
}

James VM のこと

Uva Advent Calendar 2016、 5 日目。

ʕ•͡ω•ʔ 今日は JS の Promise のことを調べてた。

James VM は Uva 用の VM です。
正確には、Uva 用の VM になる予定です。

Uva コンパイラ uvacコンパイルすると、Uva ソースコードは基本的には James VM 用のバイトコードを生成します。
この James VM バイトコードファイルの拡張子はとりあえず、.james にしておきましょう。

James VM にはイメージが必要です。
Uva のパッケージはイメージごとにインストールできます。(多分)

プロジェクト毎にイメージを作成することができますが、通常はイメージの管理が面倒くさいのでイメージは 1 つでいいんじゃね?
とか、イメージマジウザすぎじゃない?とか言われそうだよねとかでいい考えだと思ったんだけどダメかなーって思っている。

(๑´ڡ`๑) おしまい

Linux なデスクトップ環境でおすすめの 10 のアプリ

Uva Advent Calendar 4 日目。
今日は Linux なデスクトップ環境でおすすめのアプリを紹介していきたいと思います。

10 つ全部 EmacsVim になったりした 10 things を見たって?
大丈夫。今回は EmacsVim 以外のアプリを紹介するから。

Banshee

Banshee はよさげな音楽プレイヤー。
普段、音楽を聴くのに使ってるよ。

Audacious

AudaciousWinamp ライクな音楽プレイヤー。
いつもは Banshee を使っているんだけど、音楽ファイルを 1 つだけ聴きたいといったときや、Banshee の調子がおかしくなった時などに使うよ。

Firefox

Firefox はみんな知ってると思う。

LibreOffice

Excel ファイルは誰だって扱いたくない。そうだよね?
世の中は Excel ファイルで溢れている。
そんな時は LibreOffice Calc を起動しよう。

EoG (Eye of GNOME)

EoGGNOME の画像ビューアー。
起動?、起動は結構速いよ。うん。

llpp

PDF を読もうとしたけど、文字が表示されていない?
それは困ったね。
llpp のことを考えてみた?

VLC

知ってる人もいるかもしれないけど、VLC は動画プレイヤーだよ。
もちろん、Windows でも使えるんだ。

Krita

Krita はめっちゃいいよ。
まだあんまり使ったこと無いけど。
いいはずだよ。うん。

Wine

Windows のアプリを使いたいって?
Wine のことは知ってる?

OpenTTD

OpenTTD はゲームだよ!