「Groovyってどんな言語?」がちょっとおしい。
CodeZineにGroovyってどんな言語? JavaプログラマのためのGroovy入門 (1/7):CodeZineて記事が載っていたのですが、いろいろと気になる所が…
文章は読みやすく、7ページも使って結構おいしい所を一通り紹介しているのですが、それだけにちらほらと目につく瑕が残念です。
気になる所を上げてみます。
2ページ目
Groovyは、動的型付けを行う言語です。変数を利用する際、型宣言は不要です(書いてもかまいません)。実行時に値と変数の型がチェックされ、自動的に最適な型として扱われます。
「動的型付けも静的型付けも出来る」と言うべきでしょうね。必要に応じて型宣言を行い、静的型付けも出来るというのはとても重要な特徴だと思うのです。
さらに気になったのは以下の部分。
また明示的に変数の宣言をする際には、「def 変数名」という形で記述することもできます。例えば変数sに"Hello"と設定する場合は、次のような書き方ができます。
String s = "Hello" s = "Hello" def s = "Hello"
実際には「defを省略出来る」のではありません。まぁGroovy - Tutorial 1 - Getting startedにも
You can assign values to variables for later use. Try the following:
x = 1 println x
と書いてあるので、間違いと言い切る事も出来ないのですが…でも正しくない説明です。ここはちょっとややこしくて、ルーズステートメントの扱いについての理解が必要になります。
ルーズステートメントが存在する場合スクリプト自体もクラスとして展開され、
なり、例中の「String s = "Hello"」は静的型付けの変数の定義、「def s = "Hello"」は動的型付けの変数の定義としてそのrunメソッド中に入ります。
じゃあ「s = "Hello"」はどうなるのか。もちろん先に変数が宣言されていればその変数への代入文になるのですが、そうでない場合、存在しない識別子への代入となります。
で、ルーズステートメント中で存在しない識別子が使用された場合、それはスクリプトに対応して生成されるクラスのプロパティとして扱われるんですね。
なので、「String s = "Hello"」や「def s = "Hello"」は変数が定義されるんですが、「s = "Hello"」はプロパティとして定義されます。
プロパティ。他のメソッドからも参照出来ます。なので、
def foo() {println x} def x = 10 foo()
や
def foo = {->println x} def x = 10 foo()
は通りませんが
def foo() {println x} x = 10 foo()
や
def foo = {->println x} x = 10 foo()
は通ったりします。スクリプトがファイルなら、「new ファイル名」でインスタンスが生成出来るんですが、そのrunメソッドを呼び出した後なら外から取得したりも出来ます。
蛇足ですが、
def x = 10 def foo = {->println x} foo()
は通ったりしますが、これは「def foo = {->…}」がメソッド定義ではなく変数を定義してクロージャを代入しているからで、また別の話です。
また、GroovyConsoleを使っている場合defは実行のたびに消えますが
x = 10
を実行した後に
println x
とやると10が表示されたりします。これもプロパティとなっているからこそrun実行を超えてxが生き延びているんですね。
まぁ、こういった細かな差異があるので、ちゃんと理解してないとまずいと思うんですよね。
3ページ目
クラスの定義は、Javaと同様、「class クラス名」の後に続く{}内に記述をします。クラス内にはメソッドとフィールドをおくことができます。これらは「def 名前」といった形で定義をします。例えば、簡単なクラスを作成してみましょう。
class Helo { def msg Helo(s){ msg = s } def sayHelo(){ println msg } }
まず、フィールドも宣言出来ますがこれはプロパティの宣言ですね(Groovy - Groovy Beans参照)。
まぁそれはそれとして、これだとフィールド/プロパティやメソッドの定義はdefでしかできないように読めてしまいます。「必要に応じて動的型付けも静的型付けも選択出来る」点は明記して欲しい所です。プロパティやメソッドの定義こそ静的型付けが使いたくなる所なんです。私の場合、他のファイルからも使用されるようになりだすとメソッド(特に引数)やプロパティを静的型付けにしたくなって来ます。
Javaからの移行を考えると、動的型付けの緩さというのはとても不安になる所ですし、必要に応じて堅くも出来ますよ、というのは重要なんです。
まぁこのサンプルに限って言えばmsgにどんな型のオブジェクトを入れても動作するので問題ないのですが。
ルーズステートメントについては、少し上で書いたようなもうちょっと細かい仕組みに触れて欲しいと思ったんですが…うーん、それを入れると蛇足になる気もします。その辺りの説明が不要な部分のみの紹介にとどめるのが正しいでしょうね。
あと、連想配列はLinkedMapじゃ無くてLinkedHashMapですね。イージーミスでしょうけど、こういった事もちょっと信用出来ないなー、という印象につながっているのかも…
4ページ目
このページで一番気になるのは条件分岐のサンプルです。
num = new Random().nextInt(100) if (num % 2){ println "${num}は、奇数" } else { println "${num}は、偶数" }
「if (num % 2){」は無いと思うんです。ぱっと見、「割り切れるかどうか」の判定に見えませんか?「if (num % 2 == 0) {」として、thenとelseを入れ替えた方が明快ですよね。これではむしろ「if文の中はやっぱりbool型じゃないとね」と示すためのサンプルに見えてしまいます。
サンプルに対して神経質すぎるきらいも有りますが、サンプルは初心者が参考にするコードです。こういった所には気を使って欲しい所です。
nullチェックやリスト/文字列の空チェックをサンプルにするほうが良かったんじゃないかと思うのですが…
for文についても違和感がありました。
構文の基本的な使い方はJavaとはかなり異なります
から始まって詳細にgroovyのfor文の説明がされているのですが、Javaと同じ書き方も出来ますし、for文自体ほとんど使いません。for (value in list) {…}書式もJavaの拡張for文が無かった頃の遺物と言っていいと思います。あんまり詳細に説明すべき物でもないと思うんですよね。さらっとこんなのもあるよ、程度に留めておいて「後述のクロージャが有るのでfor自体ほとんど使わない」とした方が良いんじゃないかと思いました。
6ページ目
Groovy JDKについての説明で
Groovyでは、Javaの標準クラスライブラリに含まれているクラスの多くを標準で利用可能にしています。これのおかげで、多くのクラスをimportなしに利用することができます。また、Groovy独自に追加されているクラスなども多数用意されています。これらは「Groovy JDK」と呼ばれており、Java SEのかなりのクラスがそのまま持ち込まれています。
と書いてあるのですが、「多くを標準で利用可能に」とか「Java SEのかなりのクラスがそのまま持ち込まれています」とか、Javaのクラスの一部しか利用出来ないという誤解を生んでしまいそうです。実際にはあらゆるJavaのクラスが使用可能です。
groovy JDKについて「Groovy独自に追加されているクラス」だというのも誤りですね。Page Redirectionを見てみると「methods added to the JDK to make it more groovy」と有るので、groovy JDKとは「JDK(のクラス)をもっとgroovyにするために追加したメソッド群」と言うべきでしょう。