LiveScript でつまずいたこと

関数呼び出し中の do

hoge-func ham, tomato, beacon do
  a: \foo
  b: \bar

が:

hogeFunc( ham, tomato, beacon, { a: 'foo', b: 'bar' } );

になって欲しいのだが、時々こういう風になる:

hogeFunc( ham, tomato, beacon({ a: 'foo', b: 'bar' }) );

うん、beacon はただの変数で、関数じゃねーよwwwwww
もうやだこの altJS…………。
地雷だよね………(´Д⊂グスン

これは、do を使う前の引数が変数だとなるらしい。

なので、今までやっていた通り:

hoge-func ham, tomato, beacon,
  a: \foo
  b: \bar

こんな風に書くことにする。

変数?方式の関数定義は上の方に変数がいっぱい溜まるし、普通に書きたいよー

こーいうのは:

apply-options = (options) !->
  heating-power            := options.power
  number-of-people-of-cook := options.number_of_people

こんな風に書ける:

!function apply-options (options)
  heating-power            := options.power
  number-of-people-of-cook := options.number_of_people

関数を渡す関数内で呼び出し元の this を使いたい

これは私のじゃっばすくりぷよぢからが 1200 万パワーに満たないために発生したことなんだけど:

class Cook
  (@skillet) ->
    
  cook: (foods) !->
    foods.for-each (food) !->
      # skillet は Cook インスタンスのものだが、このコンテキスト(for-each に渡された関数)においては
      # @skillet はないため、あぼーんする
      @skillet.push food

こういうことをやっていたために、実行すると激しくあぼーんしたり、挙動がおかしくなっていた。
LiveScript の公式サイトを目を皿のようにして眺めたところ、~> を使うと (・∀・)イイ!! らしいことがわかったので、このように変えた:

    
  cook: (foods) !->
    # 見づらいと思うけど、矢印(`->')の横棒(`-')をチルダ(`~')にすると(`~>')、
    # lsc がうまく計らってくれる。
    foods.for-each (food) !~>
      @skillet.push food
``

あんまり怖くないと思いたい 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" );
}