🧊

0からはじめるJSX Part.4

意外に続いております。

正直プログラミングを覚えるには、こんな風に細かい仕様を見ていくよりもとりえず目標もって動かしたいものを作る・その過程で必要な仕様を調べるっていうのが一番やと思ってます。
とは言え、私自身はおさらいの意味も込めて、これからきっちり勉強しときたいなぁと思ってるので、こうしてます。

Static Types

Basic type concept will be described in this section. Primitive types, object types, variant type, and MayBeUndefined types exist in JSX.

今回は「型」についてのセクションだそうです。

  • Primirive
  • Object
  • Variant
  • MayBeUndefined

大きく分けて以上の4つがあるようです。

プリミティブ型

Primitive types, e.g. string, boolean, or number are non-nullable, immutable types.

var s : string = "hello";
var n : number = 42;
var b : boolean = true;
  • String
  • Boolean
  • Number

以上3つがプリミティブ型というらしく、null不可、イミュータブル。

Primitiveは初期のとか基本的なとかいう意味なので、まぁプログラミングに使える要素の基本的なやつ、っていう感じかしら。
確かに意識してなかったけど、文字型とか数値型とか、当たり前に使ってたアレなんやね。

nullableってなに

またもJSX - Tryに貼り付けてRunすると・・

class Test {
  static function run() : void {
    var a : string = "Hi!";
    //a = null; // cannot assign a value of type 'null' to 'string'
    //a = 20; // cannot assign a value of type 'number' to 'string'
    log a;
  }
}

という具合に、nullはダメよと怒られます。
型の違う値を入れようとしても怒られます。
JavaScriptだと後勝ちでなんでもかんでも入れ放題ですが、JSXではダメなんですね。

イミュータブルってなに

勘違いが多く含まれていたので削除+後述。
ImmutableはMutableの反対で、Mutableは・・・ミュータント!たーとr・・
なんか変幻自在な感じするでしょ?それの反対なので・・変化しないものって意味だそうな。

// これは不適切なサンプルです。

var a = "I'm immutable string!";
var b = a;

a = "Immutable, but changable.";
		
console.log(b); // I'm immutable string!
// これは不適切なサンプルです。

というわけで、変数aは(というか変数aを宣言したときに確保されたメモリのデータは)不変:Immutableなので。

これは概念を理解していたといより、経験の積み重ねとしてわかってるつもりになってたが正しいですね・・。
後述のオブジェクト型はそれと反対にMutableで、それは、

// これも不適切なサンプルです。
var a = [1,2,3,4];
var b = a;

a[0] = 0;
		
console.log(b); // [0,2,3,4]
// これも不適切なサンプルです。

ほら、変わっちゃった。
こういうのをいわゆる参照渡しとか参照型とか言うらしいです。

JavaScriptだと、他にもnullとundefinedがデータ型としてあったと思うんやけど、JSXではどういう扱いなのかしら。
試しに宣言してみたら、どっちもエラーになったっす。

ちなみに

参考:JSX 私的チュートリアル - あらびき日記

こちらを拝見する限り、int型もあるみたいです。(チュートリアルに載ってないけど
int型は整数の数値、number型は小数点含む数値を扱えるようです。
intの存在意義はわかりません・・!(たぶんメモリ的に効率が良いとかそういうの。

頂いたコメントを反映してのミュータブル

var str = "Immutable"; // str.lengthは9
str.length = 0; // String型はImmutableなので、変更不可

var arr = [1,2,3]; // arr.lengthは3
arr.length = 0; // Array型(Array.<number>)はMutableなので変更される

変数の値とかではなくて、そもそものオブジェクトの枠組みや性質が変化するかどうか。

String, Number, Int, Booleanがプリミティブ型でイミュータブル。
Date, RegExp, Function, Array, Mapがオブジェクト型でミュータブル。

オブジェクト型

Object types, e.g. string[] (array of string), functions or Date, are nullable, mutable types.

var d : Date = new Date(); // Date
var f : function():void = function() : void { log "Hi!"; };
var a : string[] = ["foo"]; // the same as Array.<string>
  • Date
  • Function
  • String[]

これらはnullありのミュータブルなもの。

Dateというか、オブジェクト?

ここではDateだけ載ってるけど、RegExpとかもどっかのサンプルで見た。
というわけで、おそらくオブジェクト型としてこういうのあるよ、Dateを見本に載せとくよって理解で良いと思ってます。

配列?

あと、このstring[ ]ってのはなんでしょう。
number[ ]ってやっても使えたので、JavaScriptの型風に見るのであれば、ただの配列って理解で良いんかな・・?
ちなみに[true, false]とか書いてもエラーにならなかったので、きっとなんでも配列なんやろな・・。

JavaScriptだと配列とは言え中身はなんでもOKでしたが、

// JavaScriptだと中身はなんでも入る
var arr1 = [1, "2", 3, "よん", {a:1, b:2}];

// JSXは配列でも何型の配列かを決める必要がある。
var arr2 = ["string", "だけでできた", "配列"] : string[];
var arr3 = [3, 1, 4, 30] : number[];
var arr4 = [3, 1, 4, 30] : Array.<number>; // こう書いても一緒

なるほど、配列も大変なんですねー。
もちろんintもあればbooleanもいけるみたい。

連想配列?

さっきの参考記事によると、Mapというものもあるそうで、これは何かというと連想配列です。
とは言えアクセスするキーが数字じゃなくなるだけで、中身としては統一する必要があるそうな。

// 連想配列でも何型の配列かを決める必要がある。
var mpp1 = {a: 1, b: 2}; // numberの連想配列
var mpp2 = {a: 1, b: 2} : Map.<number>; // こう書いても一緒
var mpp3 = {key1: "string", key2: "連想配列", key3: "です!"};

log mpp3["key1"]; // string
// log mpp3.key1 はエラー

バリアント型

Variant type, which means "no static type information," is used for interacting with existing JavaScript APIs. Some JavaScript libraries may return a variant value, which type cannot be determined at compile time. All you can do on variant values is to check equality of a variant value to another variant value. You have to cast it to another type before doing anything else on the value.

  • バリアント型は、型情報を持たない型で、既存のJavaScriptAPIを使う時に利用します。コンパイル時に型が決定されないバリアントな値を返すものが、既存のライブラリにはあります。
  • バリアント型のデータでできることは、互いの同一性(色んな意味を含む)を確認する用途だけです。
  • バリアント型のもので何かするためには、必ずキャストする必要があります。

さっぱりすぎるので、Introduction to JSXスライドの14枚目を拝借。

  • JSとのやりとりのためにvariant型がある
    • これはCのvoid*に似た、「何もできない型」
    • なにかするためには必ずcastが必要
  • variantに許される操作は==, !=, typeof, as
    • typeofはJSと同じ意味だがvariantに対してのみ許可される
  • 型安全を壊すのでなるべく使うべきでないが、 やろうと思えばなんでもできる
    • (js.global["jQuery"] as Map.)["ready"]

うん、さっぱり意味がわからない・・。
まぁその内なんか関わる時がくるやろうから、今はスルーでいいか。

一応上記の記事によると、JavaScriptでやってた型混じりの自由な配列とかを実現するには、コレを使うとのこと。

var arr1 = [1, "string", 3]: variant[];
var mpp1 = {key1: 1, key2: "string"} : Map.<variant>;

もう全部コレでやったら良いんじゃ・・とか思ってません!
おそらく最後の逃げ道として用意した感じかと。

コメントより

// JavaScript
function returnStrOrNum(args){
  return (args) ? "Str" : 10;
}

// JSX
function returnStrOrNum(args: boolean): variant {
  return (args) ? "Str" : 10;
}

仕方ないんでしょうけど、型付言語って面倒ですね・・。

キャストってなに

一度型を決めて宣言しても、時と場合によっては型を再度変えたい場合があって・・、って時はキャスト。

log false as int; // 0
log "aaa" as int; // 0
log "1" as number; // 1
log 1.5 as int; // 1
log (false as string).split("").join(","); // f,a,l,s,e

これは使いそうな予感。

MayBeUndefined型

なんぞそれ・・。

MayBeUndefined type is a meta type which indicates a value may be undefined. For example, the return type of Array.#shift() is MayBeUndefined.. When you use a MayBeUndefined value, you have to make sure of the value is not undefined.

MayBeUndefined型は値がundefinedかもしれない時に使われる型です。例えば、Arrayのもつshift関数の返す値は、このMayBeUndefined型のstringです。
undefinedになる可能性のある値を扱う場合は、値がundefinedにならないようにする必要があります。

MayBeUndefined型として指定するか、そもそもundefinedにならないようにするかしなさいということでしょうね。

function shiftOrReturnEmptyString(args : string[]) : string {
	if (args.length > 0)
		return args.shift();
	else
		return "";
}

いちおう決まりとしては、もしかしたらundefinedかも知れないことを明示する型があって、↑のshift関数みたいなやつは、配列の中身がもう無いよ!って場合にはundefinedになりうるので、MayBeUndefined型とするってこと・・?
なので、このshiftOrReturnEmptyString関数は空の文字列を返すように設計してます、ということか。

  • Array.shift関数は、配列の要素がなくなってしまうとundefinedを返すようになる。
  • そのため、このshiftOrReturnEmptyString関数は空の文字列を返すように設計している。
  • もしこの分岐を設けない場合は、関数の返り値の型は、stringではなくMayBeUndefinedになる。

まとめ

When the source code is compiled in debug mode (which is the default), the compiler will insert run-time type-checking code. An exception will be raised (or the debugger will be activated) when misuse of an undefined value as actual value is detected. Run-time type checks can be omitted by compiling the source code with the --release option.

コンパイル時には、デフォルトで型チェックのデバッグコードが挿入されるようになっています。
--releaseオプションを付けてコンパイルすることで、それを省くこともできます、と。

変数一つとっても何が入ってくるかわからんJavaScript
そのままはよろしくないので、きっちり型を明記した上で使いましょう。
とりわけnullやundefinedには気を使って、明示できるシーンではきっちり明示することで後で困ることのないように。

ってことやと思う、たぶん。
Javaからプログラミング言語を勉強した人とかは納得なんやろうけど!
大規模開発向け言語は色々制約があって大変ですねー。

コツコツいきましょ。