def構文でよりlightweightになるプログラミング

今回は6.0で追加された def 構文を紹介します。
6.0の数ある新機能の中では地味な部類に入るかもしれませんが、プログラマ的(個人的)には最も注目に値する新仕様です。


defは定数を宣言するときに使います。
従来でも定数は let constant で宣言することができましたが、def構文の新しい(素晴らしい)ところは定数の型宣言を省略できることです。つまり今まで、

let constant cb:CommandButton = {CommandButton}
let constant s:String = "foo"

と書いていたところを

def cb = {CommandButton}
def s = "foo"

のように書けるようになります。

実は curl は動的型付けのプログラミングスタイルもサポートしているので、let 文でも型宣言は従来から省略が可能でした。

let cb = {CommandButton}
let s = "foo"

しかし上記のように let で型宣言を省略した場合、変数は any 型として扱われ、コンパイラによる型チェックが行われません。一方、def で宣言した定数には初期値(右辺の式)のコンパイル時型が割り当てられます。静的型付けの恩恵を受けつつ型宣言を省略でき、プログラミングがとてもお手軽になった印象です。


def で宣言できるのは定数だけなので使えるケースは限られるように思われるかもしれませんが、しばらく6.0でプログラミングをしてみて思った感想は「意外に多用する」というものです。これまでは、いかに constant の記述を怠って変数ばっかり使っていたのか思い知らされました。(汗

def のおかげでコードの記述量が削減されただけでなく、必要がない限り let を使わなくなるため、意図しない変数の上書きを予防できるようにもなって一石二鳥な面もありました。


最後に、def を使うともっとも効果的なケースを紹介します。それは、匿名プロシージャ*1を変数で受けるケースです。
curlはプロシージャの型を、引数の種類*2と型、戻り値の型の組み合わせで区別するため、非常に厳格な型チェックを行ってくれる反面、型の記述が煩わしいという問題がありました。例えば、String型の位置引数をふたつ取り、bool型の戻り値を持つプロシージャの型は

{proc-type {String, String}:bool}

と書きます。
curlのヘルプドキュメントでも、この記法の複雑さを自覚してか、型宣言を省略して any 型の変数で受けちゃうのもアリだよ的な説明が載っていますが*3、定数でよいのであれば def 構文を使用するに限ります。

def p =
    {proc {s1:String, s2:String}:bool
        || snip
    }
{type-of p} == {proc-type {String, String}:bool} || ==> true

ちゃんとプロシージャ型も正しく割り当てられます。

*1:curlではクロージャをこう呼びます

*2:位置引数、キーワード引数、残余引数

*3:Curl開発者ガイド > 基本概念 - 構文 > プロシージャと引数 > 匿名プロシージャ > 匿名プロシージャでの any データ型の使用