あんまり怖くないと思いたい 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()
使おうなって五億回くらい言ってる。
ファイルのサイズを取得するには?
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言語でのファイルサイズ取得方法 を見ると、fseek
と SEEK_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 種類もあることは見なかったことにしておく。
窓に!窓に!
ちなみに github の Strongtalk のコードでは該当箇所はコメントアウトされていた。
*1:と言って良いんだろうか?
うどんこビリーでうどんなお正月!!
╰( ´◔ ω ◔ `)╯ やっぱり C++ も面白いな
カレー・ブルストの作り方
雨に唄えばおじさんと揚げ玉ビーチ
╰( ´◔ ω ◔ `)╯ またまた 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
を設定するのがダメってことなんだもんね。
カーネルおじさんによる美味しくできるニワトリ料理パターン
╰( ´◔ ω ◔ `)╯ 毎回記事本体じゃなくて、ナンセンス釣りタイトルを考えるのに時間を費やしてる気がしなくもない
今朝は 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
とか 後置 unless
や while
、until
もあるよ。
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 節はかっこつけなくてもいいんじゃないかとかとかとか…………。
Uva をはじめようかなー
エントリーポイント
Uva は決まったエントリーポイントを持たない言語です。
例えば、クラスの外においては Java は一切の文あるいは式(クラス・インターフェイス定義、import
文、package
文を除く)を書くことが許されていませんが、
Uva では許されています。
なので、println( "Hello, World!" );
を main()
の外に書いても構いません。
shared
のこと
shared
というのは一見キーワードのように見えますが、実のところアノテーションの 1 つです。
shared
が付いた関数や変数、クラスなどはこのソースコードの外からでも見えるようになります。
つまり、可視性を司るアノテーションです。
ループ
Uva にはループは for-in
と while
、until
の 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
式
ある型 T
の null
許容型 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 つ全部 Emacs や Vim になったりした 10 things を見たって?
大丈夫。今回は Emacs や Vim 以外のアプリを紹介するから。
Banshee
Banshee はよさげな音楽プレイヤー。
普段、音楽を聴くのに使ってるよ。
Audacious
Audacious は Winamp ライクな音楽プレイヤー。
いつもは Banshee を使っているんだけど、音楽ファイルを 1 つだけ聴きたいといったときや、Banshee の調子がおかしくなった時などに使うよ。
Firefox
Firefox はみんな知ってると思う。
LibreOffice
Excel ファイルは誰だって扱いたくない。そうだよね?
世の中は Excel ファイルで溢れている。
そんな時は LibreOffice Calc を起動しよう。
EoG (Eye of GNOME)
EoG は GNOME の画像ビューアー。
起動?、起動は結構速いよ。うん。
llpp
PDF を読もうとしたけど、文字が表示されていない?
それは困ったね。
llpp のことを考えてみた?
VLC
知ってる人もいるかもしれないけど、VLC は動画プレイヤーだよ。
もちろん、Windows でも使えるんだ。
Krita
Krita はめっちゃいいよ。
まだあんまり使ったこと無いけど。
いいはずだよ。うん。
Wine
Windows のアプリを使いたいって?
Wine のことは知ってる?
OpenTTD
OpenTTD はゲームだよ!