*vim9.txt*	For Vim バージョン 9.0.  Last change: 2021 Mar 03

		  VIMリファレンスマニュアル    by Bram Moolenaar



THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE

Vim9 script のコマンドと文法					*Vim9* *vim9*

ほとんどの文法については |eval.txt| で解説されています。このファイルには Vim9
script の新しい文法と機能について書かれています。

THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE


1.  Vim9 script とは			|Vim9-script|
2.  変更点				|vim9-differences|
3.  新しいスタイルの関数		|fast-functions|
4.  型					|vim9-types|
5.  名前空間、Import と Export		|vim9script|
6.  将来的な変更: クラス		|vim9-classes|

9.  言語設計の背景			|vim9-rationale|

==============================================================================

1. Vim9 script とは					*Vim9-script*

THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE


Vim script は、互換性の維持に気を配りながら成長してきました。そのため、古い悪
しき仕様を変更できないことが多いほか、Vi との互換性に制約を受けて、より良い解
決策を採用できなくなっています。処理は遅く、実行するたびに各行のパースが行われ
ています。

Vim9 script の主な目的は劇的な性能の向上です。これは、コマンドをより効率よく実
行できる命令にコンパイルすることで実現しています。これにより、10倍から100倍の
実行速度の向上が期待できます。

第2の目的は、Vim script 特有の文法を回避し、より一般的に使われる JavaScript や
TypeScript、Java のようなプログラミング言語に近づけることです。

パフォーマンスの向上は、100% の下位互換性を捨てることによってのみ達成しうるも
のです。たとえば、関数の引数を辞書 "a:" から利用できるようにするためには、かな
りのオーバーヘッドが必要になります。そのため、Vim9 script では、この辞書が利用
できなくなりました。その他の違いは、エラーの処理方法など、より微細なものです。

Vim9 script は以下の場所で使用することができます:
- コマンド `:def` で定義された関数の中
- コマンド `vim9script` で始まるスクリプトファイルの中
- 上記のコンテキストで定義された自動コマンド
- コマンド修飾子 `vim9cmd` が先頭に付いたコマンド

Vim9 script ファイルの中でコマンド `:function` で関数を定義すると、その中では
旧来の Vim script の記法が、最新の |scriptversion| とともに有効になります。し
かし、これは混乱を招く可能性があるため、推奨できません。

Vim9 script と旧来の Vim script は同時に利用できます。古いスクリプトを書き換え
なくとも、以前と同様に実行することが可能です。高速化が必要なコードには、`:def`
で定義する関数を使ったほうが良いかもしれません。

						*:vim9* *:vim9cmd*
:vim9[cmd] {cmd}
		Vim9 scriptの 文法と方式を使用して {cmd} を実行します。コマン
		ドを入力する時と、旧来のスクリプトや関数内で使用する時に便利で
		す。

==============================================================================

2. 旧来の Vim script からの変更点			*vim9-differences*

THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE

概要 ~

Vim9 script と `:def` で定義する関数を使用する際に最もよく遭遇する変更点の概要
は以下のとおりです:
- コメントは " ではなく、# で始めます: >
	echo "hello"   # コメント
- 行継続文字 (\) はほとんどの場合、必要ありません: >
	echo "hello "
	     .. yourName
	     .. ", how are you?"
- 多くの場所にスペースが必要になります。
- 値の代入には `:let` を使用せず、変数の宣言には `:var` を使用します: >
	var count = 0
	count += 3
- `:final` と `:const` を使用して、定数を宣言できます: >
	final matches = []		  # matches を追加
	const names = ['Betty', 'Peter']  # 変更できない
- `:final` は `:finally` の略語として使用することはできません。
- 変数と関数のスコープは、明示しない限りスクリプトローカルです。
- 関数を引数の型、戻り値の型とともに宣言します: >
	def CallMe(count: number, message: string): bool
- 関数は `:call` なしで呼び出します: >
	writefile(['done'], 'file.txt')
- `:xit`、`:t`、`:k`、`:append`、`:change`、`:insert`、`:open` と波括弧変数は
  使用できません。
- コマンドの前に範囲指定を置くときは、コロン (:) を前置しなくてはなりません: >
	:%s/this/that
- 特に指定しない限り、最新の |scriptversion| が使われます。

# から始まるコメント ~

旧来の Vim script のコメントは、ダブルクォーテーションで始めます。Vim9 script
のコメントは # で始めます。 >
	# 宣言
	var count = 0  # 出現回数

これは、ダブルクォーテーションは文字列の開始を表す文字でもあるからです。多くの
場所、特に改行を含む式の途中では、文字列とコメントの両方が現れるため、どちらを
意味しているのかわかりにくくなってしまいます。この混乱を避けるために、Vim9
script では、# のみをコメントとして認識します。このコメント形式はシェルスクリ
プトやPythonのコードと同じです。

Vi において # は行番号付きでテキストを表示します。Vim9 script では、代わりに
`:number` を使用します。 >
	101 number

可読性を向上するために、コマンドと #、コメント文の間にはスペースをおいてくださ
い: >
	var name = value # コメント
	var name = value# エラー!

旧来の Vim script では # は代替ファイル名としても使われます。Vim9 scriptでは、
代わりに %% を使う必要があります。## の代わりに %%% を使います。(すべての引数
を意味します)


Vim9 関数 ~

`:def` で定義された関数はコンパイルされます。処理の実行は多くの場合、通常の関
数に比べて10倍から100倍ほど速くなります。

多くのエラーは関数が実行される前に、コンパイルされる段階で検出されます。読みや
すく理解しやすいコードを強制するために、構文は厳密に定められています。

コンパイルは以下のいずれかのタイミングで実行されます:
- 関数が最初に呼び出されるとき
- 関数の定義されたスクリプトの中で、コマンド `:defcompile` に出会ったとき
- 関数に対してコマンド `:disassemble` が実行されたとき
- コンパイルされた関数から呼び出されたり、関数リファレンスとして使用されたとき

`:def` には `:function` の "range"、"abort"、"dict" や "closure" といったオプ
ションがありません。`:def` で定義する関数はエラー時は常に(ただし、`:silent!`が
指定されたコマンドか、`:try` ブロックの中は除く)処理を中断し、渡される範囲を受
け取らない "dict" 関数にすることはできず、常にクロージャとすることができます。

引数の型と戻り値の型を指定する必要があります。型には "any" を指定することがで
き、型のチェックは旧来の関数と同様に実行時に行われます。

引数を参照する際は、他のプログラミング言語と同様、"a:" をつけずに名前だけで指定
することができます。
引数辞書 "a:" と 引数リスト "a:000" はありません。

可変長引数を定義する場合は TypeScript のように、最後の引数として名前とlist型で
定義します。たとえば、数値の可変長引数の例は以下のとおりです: >
	def MyFunc(...itemlist: list<number>)
	   for item in itemlist
	     ...


関数と変数はデフォルトでスクリプトローカル ~
							*vim9-scopes*
Vim9 script でスクリプト直下に `:function` や `:def` を使って関数を定義すると、
関数はプリフィックス "s:" をつけた際のように、スクリプトローカルで定義されま
す。"s:" を明示することもできます。グローバルスコープの関数や変数を定義するに
はプリフィックス "g:" をつける必要があります。オートロードスクリプトで定義する
場合は、"name#" をつけます。 >
	def ThisFunction()          # スクリプトローカル
	def s:ThisFunction()        # スクリプトローカル
	def g:ThatFunction()        # グローバル
	def scriptname#function()   # オートロード

`:def` で定義した関数の中で `:function` や `:def` でネストした関数を定義するこ
とができ、定義されたブロックローカルのスコープになります。
`:def` で定義した関数の中では、スクリプトのスコープで関数を定義することはでき
ません。プリフィックス "g:" を使ってグローバルスコープの関数を定義することはで
きます。

関数をプリフィックス "s:" や "g:" をつけずに参照した場合、Vim は関数を次のよう
に探します:
- 同じ関数の中、ブロックスコープの中
- スクリプトスコープの中、インポートされたもの
- グローバル関数のリスト
しかし、明瞭にするためにもグローバル関数を参照する際はプリフィックス "g:" を付
けることを推奨します。

いずれの場合でも、関数は使用されるよりも前に定義されていなくてはなりません。使
用されるタイミングは、コマンド `:defcompile` によってコンパイルされるとき、ま
たは関数を呼び出す関数がコンパイルされているとき（戻り値の型を確認するため）で
す。

その結果として、名前空間を持たない関数や変数は通常、スクリプト内で定義されてい
るか、インポートされたものかのどちらかで見つけることができます。グローバルな関
数や変数はどこでも定義できます（どこで定義されているか、見つかるといいです
ね！）。

グローバル関数は引き続き、ほとんどいつでも定義し、削除することができます。Vim9
script でのスクリプトローカル関数は、スクリプトが読み込まれたときに一度定義さ
れたきり、削除や置き換えはできません。

関数のコンパイルや、関数の呼び出しが未定義の関数に遭遇したとき、自動コマンド
|FuncUndefined| は呼び出されません。必要であればオートロード関数を使用したり、
旧来の関数を呼び出すことで |FuncUndefined| イベントが発生します。


デフォルトでは Vim9 script の再読み込みにより関数と変数がクリアされる ~
							*vim9-reload*
旧来の Vim script を2回目に読み込んだときは、何も削除されることはなく、コマン
ドはすでにある変数や関数を置き換えて新しいものを作ります。

Vim9 script を2回目に読み込んだときは、存在するすべてのスクリプトローカルの関
数や変数は削除され、クリーンな状態から開始します。これはプラグインを開発中に、
新しいバージョンを試す際には便利です。いずれかの名前を変えたとしても、古い名前
が残る心配はありません。

消さずに残すには、以下を使用します: >
	vim9script noclear

これを使用することで、再読み込みの際に任意の場所で `finish` コマンドにより脱出
することができます。たとえば、バッファローカルオプションが設定されているとき: >
	vim9script noclear
	setlocal completefunc=SomeFunc
	if exists('*g:SomeFunc') | finish | endif
	def g:SomeFunc()
	....


:var、:final や :const で宣言する変数 ~
						*vim9-declaration* *:var*
ローカル変数は `:var` で定義する必要があります。ローカル定数は `:final` または
`:const` で定義する必要があります。このセクションでは、両者を "変数" と呼ぶこ
とにします。

変数はスクリプトローカルや、関数、コードブロックのスコープで定義できます: >
	vim9script
	var script_var = 123
	def SomeFunc()
	  var func_var = script_var
	  if cond
	    var block_var = func_var
	  ...

変数は、定義されたコードブロックか、ネストされた配下のブロックで参照することが
できます。コードブロックが終わったあとの処理から参照することはできません: >
	if cond
	   var inner = 5
	else
	   var inner = 0
	endif
	echo inner  # エラー!

参照したい場合には、ブロックよりも前で宣言しなくてはなりません: >
	var inner: number
	if cond
	   inner = 5
	else
	   inner = 0
	endif
	echo inner

意図的に続く処理から変数を隠したいとき、ブロックを使うことができます: >
	{
	   var temp = 'temp'
	   ...
	}
	echo temp  # エラー!

変数を型付きで、かつ初期値なしで宣言した場合、その値はゼロ、False、または空で
初期化されます。

Vim9 script では `:let` は使用できません。すでに存在する変数に題してはコマンド
を使用せずに代入します。グローバル変数、ウィンドウ変数、タブ変数、バッファ変
数、そして Vim の定義済変数についても同様です。
変数は `:unlet` によって削除することもできます。

変数と関数と関数の引数は、同じスクリプトファイル内で、すでに定義された、または
インポートされた変数と関数をシャドーイングすることはできません。一方で変数は
Ex コマンドをシャドーイングするので、必要であれば変数の名前を変更してくださ
い。

グローバル変数やユーザー定義関数の前には、スクリプトレベルでも "g: "を付けなけ
ればなりません。 >
	vim9script
	var script_local = 'text'
	g:global = 'value'
	var Funcref = g:ThatFunction

現在、`&opt = value` は "opt" オプションに値を設定する目的で使用されているた
め、`:substitute` コマンドをリピートする目的 ":&" を使用することはできません。


定数 ~
						*vim9-const* *vim9-final*
定数の働きは言語によって異なります。別の値を代入できない変数を定数とする場合も
あります。JavaScript がその一例です。また、値そのものを不変にすることもあり、
たとえばリスト定数の内容を変更することができないとしている場合もあります。
Vim9ではこのどちらも定義することができます。

変数とその値、両方を定数とするには、`:const` を使用します。何らかの複合的な値
が変更できないようにする際に使用します。例: >
	const myList = [1, 2]
	myList = [3, 4]		# エラー!
	myList[0] = 9		# エラー!
	myList->add(3)		# エラー!
<							*:final*
変数の変更のみを禁止するには、`:final` を使用します。この場合は、中の値自体を
変えることはできます。Java でよく知られるものです。例: >
	final myList = [1, 2]
	myList = [3, 4]		# エラー!
	myList[0] = 9		# OK
	myList->add(3)		# OK

一般に、定数はすべて大文字 (例: ALL_CAPS) で書かれますが、必ずしもそうしなくて
も構いません。

定数宣言は値そのものにのみ適用され、参照先の変数には影響しません。 >
	final females = ["Mary"]
	const NAMES = [["John", "Peter"], females]
	NAMES[0] = ["Jack"]     # エラー!
	NAMES[0][0] = "Jack"    # エラー!
	NAMES[1] = ["Emma"]     # エラー!
	NAMES[1][0] = "Emma"    # OK, females[0] == "Emma"


:call と :eval は不要に ~

関数は `:call` なしで呼ぶことができます: >
	writefile(lines, 'file')
`:call` は引き続き使用できますが、やめたほうが良いでしょう。

メソッド呼び出しには `eval` は必要ありません。Exコマンドと同名の識別子ではない
限り、直接に識別子から呼び出すことができます。関数の場合は、"(" または "->"の
どちらかを改行せずに続けなければなりません。例: >
	myList->add(123)
	g:myList->add(123)
	[1, 2, 3]->Process()
	{a: 1, b: 2}->Process()
	"foobar"->Process()
	("foobar")->Process()
	'foobar'->Process()
	('foobar')->Process()

一部の関数と Ex コマンドが紛らわしい場合、コロン (:) を前置することでそれが Ex
コマンドであることを明示することができます。たとえば、`:substitute` コマンドと
`substitute()` が該当します。`substitute(` で始まる場合は関数呼び出しですが、
コロンを前置することでコマンドを代わりに使用することができます: >
	:substitute(pattern (replacement (

Note 変数は使用する前に宣言する必要がありますが、関数は宣言するより前に使用で
きる点に注意してください。これは関数の循環参照を可能にするためです。関数を名前
で探さなければならないので、少し効率が悪いです。また、関数名のタイプミスは、関
数が呼び出されるときまで見つかりません。


function() は不要に ~

ユーザー定義の関数は、`function()` を使わずとも関数リファレンスとして使用する
ことができます。引数の型と戻り値の型がチェックされます。関数はすでに定義されて
いる必要があります。 >

	var Funcref = MyFunction

`function()` を使って "func" 型のリファレンスを得た場合、その関数は任意の個数
の引数と任意の戻り値の型を持つものとされます。この場合、関数は後から宣言できま
す。


ラムダ式には -> の代わりに => を使う ~

旧来のスクリプトでは "->" はメソッド呼び出しとラムダ式で混同するおそれがありま
す。また、"{" が見つかったとき、パーサーはラムダ式と辞書の開始を見分けねばなら
ず、そしてそれは引数の型指定により複雑になっています。

この問題を回避するため、Vim9 script ではラムダ式のために違う書式を使用し、それ
は Javascript に似ています: >
	var Lambda = (arg) => expression

"=>" まで含めて、ラムダ式の引数の定義の中では改行することはできません。これは
OKです: >
	filter(list, (k, v) =>
			v > 0)
以下のように記述することはできません: >
	filter(list, (k, v)
			=> v > 0)
以下のように記述することもできません: >
	filter(list, (k,
			v) => v > 0)
ただし、バックスラッシュを使ってパースする前に行をつなげることができます: >
	filter(list, (k,
		\	v)
		\	=> v > 0)

加えて、ラムダ式には {} に複数のステートメントを含むことができます: >
	var Lambda = (arg) => {
		g:was_called = 'yes'
		return expression
	    }
NOT IMPLEMENTED YET

							*vim9-curly*
辞書リテラルの "{" がステートメントブロックと認識されてしまうのを回避するため
には、括弧で包みます: >
	var Lambda = (arg) => ({key: 42})

さらに、コマンドブロックの開始と混同してしまう場合: >
	({
	    key: value
	 })->method()


自動行継続 ~

多くの場合、式が次の行に続くことは明らかです。継続行の先頭に行継続のためのバッ
クスラッシュ (|line-continuation| 参照) を置く必要はありません。たとえば、複数
行にまたぐリストの場合: >
	var mylist = [
		'one',
		'two',
		]
辞書の場合: >
	var mydict = {
		one: 1,
		two: 2,
		}
関数の呼び出し: >
	var result = Func(
			arg1,
			arg2
			)

角カッコ []、波カッコ {}、または丸カッコの中‘以外で’二項演算子御使用する場
合、その前後で改行することができます。例: >
	var text = lead
		   .. middle
		   .. end
	var total = start +
		    end -
		    correction
	var result = positive
			? PosFunc(arg)
			: NegFunc(arg)

"->" を使用したメソッド呼び出し、そしてドット (.) を使用したメンバー参照の場
合、その前に改行を置くことができます: >
	var result = GetBuilder()
			->BuilderSetWidth(333)
			->BuilderSetHeight(777)
			->BuilderBuild()
	var result = MyDict
			.member

複数のコマンドのリストを引数に持つコマンドでは、行の先頭に置かれた文字 | は行
継続を表します: >
	autocmd BufNewFile *.match if condition
		|   echo 'match'
		| endif

<							*E1050*
行頭の演算子と識別できるようにするために、範囲指定の前にはコロンを置きま
す。"start" と print をつなげる例: >
	var result = start
	+ print
これは以下の記述と同じです: >
	var result = start + print

次のように書くと、"start" を代入して、1行表示します: >
	var result = start
	:+ print

Note |+cmd| の引数にはコロンは不要です: >
	edit +6 fname

関数の定義部においても、引数の間で改行をおくことができます: >
	def MyFunc(
		text: string,
		separator = '-'
		): string

継続行を識別することは容易ではないため、コマンドの解析はより厳格化されていま
す。たとえば、一行目のエラーにより、2行目は別のコマンドとみなされます: >
	popup_create(some invalid expression, {
	   exit_cb: Func})
ここで "exit_cb: Func})" は実際に有効なコマンドです: 変更をファイル
"_cb: Func})" に保存して閉じます。Vim9 script の中ではこの種のミスを回避するた
めに、コマンド名と引数の間にはスペースを置かなくてはなりません。

ただし、コマンドの引数に置いたコマンドは認識されません。たとえば、
"windo echo expr" に続く "expr" の式の中で改行しても認識されません。


Notes:
- "enddef" は継続行の先頭に置くことはできません。それは関数の終端を意味します。
- 代入式の左辺を複数の行に分割できません。特にリストのアンパック |:let-unpack|
  を使用する場合は注意が必要です。これはOKです: >
	[var1, var2] =
		Func()
<  以下のように記述することはできません: >
	[var1,
	    var2] =
		Func()
- `:echo` や `:execute` のようなコマンドの引数は複数の行に分割できません。これ
  はOKです: >
	echo [1,
		2] [3,
			4]
<  以下のように記述することはできません: >
	echo [1, 2]
		[3, 4]


波括弧変数の廃止 ~

波括弧変数 |curly-braces-names| は使用できません。


辞書リテラル ~

従来、Vim は波括弧 {} で辞書リテラルの表記をサポートしてきました: >
	let dict = {'key': value}

後に、辞書にシンプルなキーを使用することが非常に一般的であることが明らかになっ
たため、キーをクォーテーションなしで指定できる表記が後方互換的に導入されまし
た: >
	let dict = #{key: value}

しかし、この #{} という表記は他の言語に比べて異色なものです。キーには式よりも
リテラルを使うほうが一般的で、JavaScript が使っている構文を考えると、辞書リテ
ラルに {} の表記を使うほうがずっと便利です: >
	var dict = {key: value}

これは英数字、アンダースコアとダッシュのキーで利用できます。異なる文字を使用す
る場合は、シングルクォートまたはダブルクォートで囲まれた文字列を使用します: >
	var dict = {'key with space': value}
	var dict = {"key\twith\ttabs": value}
	var dict = {'': value}  		# 空のキー

キーに式を使用する必要がある場合は、JavaScript と同様に角括弧を使用することが
できます: >
	var dict = {["key" .. nr]: value}

キーの型には、文字列、数値、bool、floatのいずれかを指定できます。その他の型の
場合はエラーが発生します。数字は、[] をつけてもつけなくても与えられます: >
	var dict = {123: 'without', [456]: 'with'}
	echo dict
	{'456': 'with', '123': 'without'}

:xit、:t、:k、:append、:change、:insert の廃止 ~

これらのコマンドは容易にローカル変数の名前と混同します。
`:x` や `:xit` の代わりに `:exit` を使用できます。
`:t` の代わりに `:copy` を使用できます。
`:k` の代わりに `:mark` を使用できます。

比較 ~

オプション 'ignorecase' は文字列の比較には作用しません。


For ループ ~

旧来の Vim script では、リストのループ内で現在または前の項目を削除するための
for ループをつくるために幾つかのトリックがあります。Vim9 script では、単純にイ
ンデックスを使用することで、リストから削除された場合はスキップされます。
旧来のスクリプトの例: >
	let l = [1, 2, 3, 4]
	for i in l
	   echo i
	   call remove(l, index(l, i))
	endfor
出力は以下の通り:
	1
	2
	3
	4
コンパイルされた Vim9 script での出力は以下の通り:
	1
	3
一般的に、反復しているリストを変更してはいけません。必要であれば最初にコピーを
作ります。


スペース ~

Vim9 script ではスペースの適切な使用を推奨しています。以下のような記述はできま
せん: >
	var name=234	# エラー!
	var name= 234	# エラー!
	var name =234	# エラー!
"=" の前後にはスペースを置く必要があります: >
	var name = 234	# OK
コメント先頭の # の前にもスペースが必要です: >
	var name = 234# エラー!
	var name = 234 # OK

多くの演算子の前後にはスペースが必要です。

部分リストの ":" の前後には、先頭と末尾の場合を除いてはスペースが必要です: >
	otherlist = mylist[v : count]  	# v:count は違う意味になる
	otherlist = mylist[:]		# リストのコピーを作る
	otherlist = mylist[v :]
	otherlist = mylist[: v]

スペースをおいてはいけない場合:
- 関数の名前と "(" の間: >
	Func (arg)	   # エラー!
	Func
	     \ (arg)	   # エラー!
	Func
	      (arg)	   # エラー!
	Func(arg)	   # OK
	Func(
	      arg)	   # OK
	Func(
	      arg	   # OK
	      )


条件と式 ~

条件と式は、他の言語とおよそ同じように扱われます。いくつかの値は旧来の Vim
script と扱いが異なります:
	値		旧来の Vim script	Vim9 script ~
	0		falsy			falsy
	1		truthy			truthy
	99		truthy			エラー!
	"0"		falsy			エラー!
	"99"		truthy			エラー!
	"text"		falsy			エラー!

"??" 演算子か "!" を使用している場合はエラーとなることはなく、すべての値は
falsy か truthy として評価されます。これは JavaScript とほぼ同じですが、空の
リストと辞書は falsy として評価されます:

	型		真と評価される値 ~
	bool		true, v:true または 1
	number		非0
	float		非0
	string		空文字列以外
	blob		空ブロブ以外
	list		空リスト以外 (JavaScript とは異なります)
	dictionary	空辞書以外 (JavaScript とは異なります)
	func		when there is a function name
	special		true または v:true
	job		非 NULL
	channel		非 NULL
	class		非 NULL
	object		非 NULL (TODO: isTrue() が true を返すとき)

真偽値演算子 "||" と "&&" は、値が真偽値、0または1であることを期待します:
>
	1 || false   == true
	0 || 1       == true
	0 || false   == false
	1 && true    == true
	0 && 1       == false
	8 || 0	     エラー!
	'yes' && 0   エラー!
	[] || 99     エラー!

"!" を使って論理否定をすると、どのような型に対しても結果は真偽値になります。
"!!" と二重論理否定をすることで、あらゆる型を真偽値に変換することができます: >
	!'yes'			== false
	!![]			== false
	!![1, 2, 3]		== true

文字列の結合に `..` を使用すると、すべての単純型の被演算子は常に文字列に変換さ
れます: >
	'hello ' .. 123  == 'hello 123'
	'hello ' .. v:true  == 'hello true'

単純型とは、文字列 (string)、数値 (float)、特殊値 (special) と真偽値 (bool) で
す。他の型では |string()| が使用できます。

							*false* *true* *null*
Vim9 script では "true" を v:true として、"false" を v:false として、そして
"null" を v:null として使うことができます。真偽値を文字列に変換するとき、旧来
のスクリプトのような "v:false" と "v:true" ではなく、"false" と "true" を使用
します。"v:none" は変わらず、JSONでのみ使用され、他の言語には相当するものはあ
りません。

文字列に対してインデックス [idx] や [idx : idx] を使用すると、バイト単位ではな
く文字単位のインデックスとして扱われます。結合文字が含まれています。例: >
	echo 'bár'[1]
旧来の Vim script ではこれは文字 0xc3 (不正な文字) となりますが、Vim9 script
では文字列 'á' が得られます。
負のインデックスを指定すると、文字列の末尾から数えられます。"[-1]" は最後の文
字です。
最後の文字を除外するには |slice()| を使用します。
インデックスが範囲外の場合は、空文字列になります。

旧来のスクリプトでは "++var" と "--var" は寡黙に処理され、何の効果ももたらしま
せん。これは Vim9 script ではエラーになります。

ゼロから始まる数値は8進数とはみなされません、"0o" から始まる数値だけが8進数と
みなされます: "0o744"。|scriptversion-4|


気をつけるべきこと ~
							*vim9-gotchas*
Vim9 は、一般的なプログラミング言語に近づくように設計されていますが、同時に旧
来の Vim コマンドをサポートしようとしています。そのため、いくつかの妥協をしな
ければなりませんでした。ここでは、意外と知られていないことをまとめてみました。

Exコマンドの範囲指定にはコロンを前置する必要があります。 >
	->		  旧来の Vim: 前の行を右にシフト
	->func()	  Vim9: 継続行におけるメソッド呼び出し
	:->		  Vim9: 前の行を右にシフト

	%s/a/b		  旧来の Vim: すべての行を置換
	x = alongname
	     % another	  Vim9: 継続行の剰余演算
	:%s/a/b		  Vim9: すべての行を置換
	't		  旧来の Vim: マーク t へのジャンプ
	'text'->func()	  Vim9: メソッド呼び出し
	:'t		  Vim9: マーク t へのジャンプ

いくつかのExコマンドは Vim9 script の代入式と紛らわしくなります: >
	g:name = value    # 代入
	g:pattern:cmd	  # 不正なコマンド - エラー
	:g:pattern:cmd	  # :グローバルコマンド

`:def` で定義した関数はすべてコンパイルされます。旧来の関数は途中で脱出するこ
とができ、それ以降の行はパースされません: >
	func Maybe()
	  if !has('feature')
	    return
	  endif
	  use-feature
	endfunc
Vim9 関数はすべてコンパイルされます: >
	def Maybe()
	  if !has('feature')
	    return
	  endif
	  use-feature  # コンパイルエラーが発生する可能性がある
	enddef
応急的に、2つの関数に分けることができます: >
	func Maybe()
	  if has('feature')
	    call MaybeInner()
	  endif
	endfunc
	if has('feature')
	  def MaybeInner()
	    use-feature
	  enddef
	endif
また、偽として評価される定数式の条件をもった `if` の配下にサポート外のコードを
置くことができます: >
	def Maybe()
	  if has('feature')
	    use-feature
	  endif
	enddef
<							*vim9-user-command*
関数のコンパイルによる他の副作用として、ユーザーコマンドの存在がコンパイルの時
点でチェックされます。ユーザーコマンドが後で定義されている場合、エラーとなりま
す。これはOKです: >
	command -nargs=1 MyCommand echom <q-args>
	def Works()
	  MyCommand 123
	enddef
これは "MyCommand" が定義されていないというエラーが発生します: >
	def Works()
	  command -nargs=1 MyCommand echom <q-args>
	  MyCommand 123
	enddef
回避策は、`:execute` を使用して間接的にコマンドを呼び出すことです: >
	def Works()
	  command -nargs=1 MyCommand echom <q-args>
	  execute 'MyCommand 123'
	enddef

Note 認識されていないコマンドを "|" でつなぐと、その後のコマンドは認識されませ
ん。次のような記述は `endif` がないというエラーになります: >
	def Maybe()
	  if has('feature') | use-feature | endif
	enddef

その他の変更点 ~

パターンは、明示的に上書きされない限り 'magic' が設定されている状態と同様に作
用します。
オプション 'edcompatible' の値は使用されません。
オプション 'gdefault' の値は使用されません。

また、このwikiも参考になるでしょう。これはVim9 scriptのアーリーアダプターによっ
て書かれました: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md

==============================================================================

3. New style functions					*fast-functions*

							*:def* *E1028*
:def[!] {name}([arguments])[: {return-type}]
			Define a new function by the name {name}.  The body of
			the function follows in the next lines, until the
			matching `:enddef`. *E1073*
							*E1011*
			The {name} must be less than 100 bytes long.
					*E1003* *E1027* *E1056* *E1059*
			The type of value used with `:return` must match
			{return-type}.  When {return-type} is omitted or is
			"void" the function is not expected to return
			anything.
							*E1077* *E1123*
			{arguments} is a sequence of zero or more argument
			declarations.  There are three forms:
				{name}: {type}
				{name} = {value}
				{name}: {type} = {value}
			The first form is a mandatory argument, the caller
			must always provide them.
			The second and third form are optional arguments.
			When the caller omits an argument the {value} is used.

			The function will be compiled into instructions when
			called, or when `:disassemble` or `:defcompile` is
			used.  Syntax and type errors will be produced at that
			time.

			It is possible to nest `:def` inside another `:def` or
			`:function` up to about 50 levels deep.
							*E1117*
			[!] is used as with `:function`.  Note that
			script-local functions cannot be deleted or redefined
			later in Vim9 script.  They can only be removed by
			reloading the same script.

					*:enddef* *E1057* *E1152* *E1173*
:enddef			End of a function defined with `:def`. It should be on
			a line by its own.

You may also find this wiki useful.  It was written by an early adopter of
Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md

If the script the function is defined in is Vim9 script, then script-local
variables can be accessed without the "s:" prefix.  They must be defined
before the function is compiled.  If the script the function is defined in is
legacy script, then script-local variables must be accessed with the "s:"
prefix if they do not exist at the time of compiling.

						*:defc* *:defcompile*
:defc[ompile]		Compile functions defined in the current script that
			were not compiled yet.
			This will report errors found during the compilation.

						*:disa* *:disassemble*
:disa[ssemble] {func}	Show the instructions generated for {func}.
			This is for debugging and testing. *E1061*
			Note that for command line completion of {func} you
			can prepend "s:" to find script-local functions.

:disa[ssemble] profile {func}
			Like `:disassemble` but with the instructions used for
			profiling.

:disa[ssemble] debug {func}
			Like `:disassemble` but with the instructions used for
			debugging.

Limitations ~

Local variables will not be visible to string evaluation.  For example: >
	def MapList(): list<string>
	  var list = ['aa', 'bb', 'cc', 'dd']
	  return range(1, 2)->map('list[v:val]')
	enddef

The map argument is a string expression, which is evaluated without the
function scope.  Instead, use a lambda: >
	def MapList(): list<string>
	  var list = ['aa', 'bb', 'cc', 'dd']
	  return range(1, 2)->map((_, v) => list[v])
	enddef

For commands that are not compiled, such as `:edit`, backtick expansion can be
used and it can use the local scope.  Example: >
	def Replace()
	  var fname = 'blah.txt'
	  edit `=fname`
	enddef

Closures defined in a loop will share the same context.  For example: >
	var flist: list<func>
	for i in range(5)
	  var inloop = i
	  flist[i] = () => inloop
	endfor
	echo range(5)->map((i, _) => flist[i]())
	# Result: [4, 4, 4, 4, 4]
<							*E1271*
A closure must be compiled in the context that it is defined in, so that
variables in that context can be found.  This mostly happens correctly, except
when a function is marked for debugging with `breakadd` after it was compiled.
Make sure the define the breakpoint before compiling the outerh function.

The "inloop" variable will exist only once, all closures put in the list refer
to the same instance, which in the end will have the value 4.  This is
efficient, also when looping many times.  If you do want a separate context
for each closure call a function to define it: >
	def GetClosure(i: number): func
	  var infunc = i
	  return () => infunc
	enddef

	var flist: list<func>
	for i in range(5)
	  flist[i] = GetClosure(i)
	endfor
	echo range(5)->map((i, _) => flist[i]())
	# Result: [0, 1, 2, 3, 4]

In some situations, especially when calling a Vim9 closure from legacy
context, the evaluation will fail.  *E1248*


Converting a function from legacy to Vim9 ~
					*convert_legacy_function_to_vim9*
These are the most changes that need to be made to convert a legacy function
to a Vim9 function:

- Change `func` or `function` to `def`.
- Change `endfunc` or `endfunction` to `enddef`.
- Add types to the function arguments.
- If the function returns something, add the return type.
- Change comments to start with # instead of ".

  For example, a legacy function: >
	func MyFunc(text)
	  " function body
	endfunc
<  Becomes: >
	def MyFunc(text: string): number
	  # function body
	enddef

- Remove "a:" used for arguments. E.g.: >
	return len(a:text)
<  Becomes: >
	return len(text)

- Change `let` used to declare a variable to `var`.
- Remove `let` used to assign a value to a variable.  This is for local
  variables already declared and b: w: g: and t: variables.

  For example, legacy function: >
	  let lnum = 1
	  let lnum += 3
	  let b:result = 42
<  Becomes: >
	  var lnum = 1
	  lnum += 3
	  b:result = 42

- Insert white space in expressions where needed.
- Change "." used for concatenation to "..".

  For example, legacy function: >
	  echo line(1).line(2)
<  Becomes: >
	  echo line(1) .. line(2)

- line continuation does not always require a backslash: >
  	echo ['one',
		\ 'two',
		\ 'three'
		\ ]
<  Becomes: >
	echo ['one',
		'two',
		'three'
		]

==============================================================================

4. Types					*vim9-types*
					*E1008* *E1009* *E1010* *E1012*
					*E1013* *E1029* *E1030*
The following builtin types are supported:
	bool
	number
	float
	string
	blob
	list<{type}>
	dict<{type}>
	job
	channel
	func
	func: {type}
	func({type}, ...)
	func({type}, ...): {type}
	void

Not supported yet:
	tuple<a: {type}, b: {type}, ...>

These types can be used in declarations, but no simple value will actually
have the "void" type.  Trying to use a void (e.g. a function without a
return value) results in error *E1031*  *E1186* .

There is no array type, use list<{type}> instead.  For a list constant an
efficient implementation is used that avoids allocating lot of small pieces of
memory.
							*E1005* *E1007*
A partial and function can be declared in more or less specific ways:
func				any kind of function reference, no type
				checking for arguments or return value
func: void			any number and type of arguments, no return
				value
func: {type}			any number and type of arguments with specific
				return type

func()				function with no argument, does not return a
				value
func(): void			same
func(): {type}			function with no argument and return type

func({type})			function with argument type, does not return
				a value
func({type}): {type}		function with argument type and return type
func(?{type})			function with type of optional argument, does
				not return a value
func(...{type})			function with type of variable number of
				arguments, does not return a value
func({type}, ?{type}, ...{type}): {type}
				function with:
				- type of mandatory argument
				- type of optional argument
				- type of variable number of arguments
				- return type

If the return type is "void" the function does not return a value.

The reference can also be a |Partial|, in which case it stores extra arguments
and/or a dictionary, which are not visible to the caller.  Since they are
called in the same way the declaration is the same.

Custom types can be defined with `:type`: >
	:type MyList list<string>
Custom types must start with a capital letter, to avoid name clashes with
builtin types added later, similarly to user functions.
{not implemented yet}

And classes and interfaces can be used as types: >
	:class MyClass
	:var mine: MyClass

	:interface MyInterface
	:var mine: MyInterface

	:class MyTemplate<Targ>
	:var mine: MyTemplate<number>
	:var mine: MyTemplate<string>

	:class MyInterface<Targ>
	:var mine: MyInterface<number>
	:var mine: MyInterface<string>
{not implemented yet}


Variable types and type casting	~
							*variable-types*
Variables declared in Vim9 script or in a `:def` function have a type, either
specified explicitly or inferred from the initialization.

Global, buffer, window and tab page variables do not have a specific type, the
value can be changed at any time, possibly changing the type.  Therefore, in
compiled code the "any" type is assumed.

This can be a problem when the "any" type is undesired and the actual type is
expected to always be the same.  For example, when declaring a list: >
	var l: list<number> = [1, g:two]
At compile time Vim doesn't know the type of "g:two" and the expression type
becomes list<any>.  An instruction is generated to check the list type before
doing the assignment, which is a bit inefficient.
						*type-casting* *E1104*
To avoid this, use a type cast: >
	var l: list<number> = [1, <number>g:two]
The compiled code will then only check that "g:two" is a number and give an
error if it isn't.  This is called type casting.

The syntax of a type cast is:  "<" {type} ">".  There cannot be white space
after the "<" or before the ">" (to avoid them being confused with
smaller-than and bigger-than operators).

The semantics is that, if needed, a runtime type check is performed.  The
value is not actually changed.  If you need to change the type, e.g. to change
it to a string, use the |string()| function.  Or use |str2nr()| to convert a
string to a number.


Type inference ~
							*type-inference*
In general: Whenever the type is clear it can be omitted.  For example, when
declaring a variable and giving it a value: >
	var name = 0		# infers number type
	var name = 'hello'	# infers string type

The type of a list and dictionary comes from the common type of the values.
If the values all have the same type, that type is used for the list or
dictionary.  If there is a mix of types, the "any" type is used. >
	[1, 2, 3]	list<number>
	['a', 'b', 'c']	list<string>
	[1, 'x', 3]	list<any>

The common type of function references, if they do not all have the same
number of arguments, uses "(...)" to indicate the number of arguments is not
specified.  For example: >
	def Foo(x: bool)
	enddef
	def Bar(x: bool, y: bool)
	enddef
	var funclist = [Foo, Bar]
	echo funclist->typename()
Results in:
	list<func(...)>

For script-local variables in Vim9 script the type is checked, also when the
variable was declared in a legacy function.

When a type has been declared this is attached to a List or Dictionary.  When
later some expression attempts to change the type an error will be given: >
	var ll: list<number> = [1, 2, 3]
	ll->extend(['x'])  # Error, 'x' is not a number

If the type is not declared then it is allowed to change: >
	[1, 2, 3]->extend(['x'])  # result: [1, 2, 3, 'x']

For a variable declaration an inferred type matters: >
	var ll = [1, 2, 3]
	ll->extend(['x'])  # Error, 'x' is not a number
That is because the declaration looks like a list of numbers, thus is
equivalent to: >
	var ll: list<number> = [1, 2, 3]
If you do want a more permissive list you need to declare the type: >
	var ll: list<any = [1, 2, 3]
	ll->extend(['x'])  # OK


Stricter type checking ~
							*type-checking*
In legacy Vim script, where a number was expected, a string would be
automatically converted to a number.  This was convenient for an actual number
such as "123", but leads to unexpected problems (and no error message) if the
string doesn't start with a number.  Quite often this leads to hard-to-find
bugs. e.g.: >
	echo 123 == '123'
<	1 ~
With an accidental space: >
	echo 123 == ' 123'
<	0 ~
							*E1206* *E1210* *E1212*
In Vim9 script this has been made stricter.  In most places it works just as
before if the value used matches the expected type.  There will sometimes be
an error, thus breaking backwards compatibility.  For example:
- Using a number other than 0 or 1 where a boolean is expected.  *E1023*
- Using a string value when setting a number option.
- Using a number where a string is expected.   *E1024* *E1105*

One consequence is that the item type of a list or dict given to |map()| must
not change, if the type was declared.  This will give an error in Vim9
script: >
	var mylist: list<number> = [1, 2, 3]
	echo map(mylist, (i, v) => 'item ' .. i)
<	E1012: Type mismatch; expected number but got string in map() ~

Instead use |mapnew()|, it creates a new list: >
	var mylist: list<number> = [1, 2, 3]
	echo mapnew(mylist, (i, v) => 'item ' .. i)
<	['item 0', 'item 1', 'item 2'] ~

If the item type was not declared or determined to be "any" it can change to a
more specific type.  E.g. when a list of mixed types gets changed to a list of
strings: >
	var mylist = [1, 2.0, '3']
	# typename(mylist) == "list<any>"
	map(mylist, (i, v) => 'item ' .. i)
	# typename(mylist) == "list<string>", no error

There is a subtle difference between using a list constant directly and
through a variable declaration.  Because of type inference, when using a list
constant to initialize a variable, this also sets the declared type: >
	var mylist = [1, 2, 3]
	# typename(mylist) == "list<number>"
	echo map(mylist, (i, v) => 'item ' .. i)  # Error!

When using the list constant directly, the type is not declared and is allowed
to change: >
	echo map([1, 2, 3], (i, v) => 'item ' .. i)  # OK

The reasoning behind this is that when a type is declared and the list is
passed around and changed, the declaration must always hold.  So that you can
rely on the type to match the declared type.  For a constant this is not
needed.

								*E1158*
Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use
|flattennew()| instead.  Since |flatten()| is intended to always change the
type, it can not be used in Vim9 script.

			 *E1211* *E1217* *E1218* *E1219* *E1220* *E1221*
			 *E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
			 *E1228* *E1238* *E1250* *E1251* *E1252* *E1253*
			 *E1256*
Types are checked for most builtin functions to make it easier to spot
mistakes.

==============================================================================

5. Namespace, Import and Export
					*vim9script* *vim9-export* *vim9-import*

A Vim9 script can be written to be imported.  This means that some items are
intentionally exported, made available to other scripts.  When the exporting
script is imported in another script, these exported items can then be used in
that script.  All the other items remain script-local in the exporting script
and cannot be accessed by the importing script.

This mechanism exists for writing a script that can be sourced (imported) by
other scripts, while making sure these other scripts only have access to what
you want them to.  This also avoids using the global namespace, which has a
risc of name collisions.  For example when you have two plugins with similar
functionality.

You can cheat by using the global namespace explicitly.  That should be done
only for things that really are global.


Namespace ~
							*vim9-namespace*
To recognize a file that can be imported the `vim9script` statement must
appear as the first statement in the file (see |vim9-mix| for an exception).
It tells Vim to interpret the script in its own namespace, instead of the
global namespace.  If a file starts with: >
	vim9script
	var myvar = 'yes'
Then "myvar" will only exist in this file.  While without `vim9script` it would
be available as `g:myvar` from any other script and function.
							*E1101*
The variables at the file level are very much like the script-local "s:"
variables in legacy Vim script, but the "s:" is omitted.  And they cannot be
deleted.

In Vim9 script the global "g:" namespace can still be used as before.  And the
"w:", "b:" and "t:" namespaces.  These have in common that variables are not
declared and they can be deleted.

A side effect of `:vim9script` is that the 'cpoptions' option is set to the
Vim default value, like with: >
	:set cpo&vim
One of the effects is that |line-continuation| is always enabled.
The original value of 'cpoptions' is restored at the end of the script, while
flags added or removed in the script are also added to or removed from the
original value to get the same effect.  The order of flags may change.
In the |vimrc| file sourced on startup this does not happen.

							*vim9-mix*
There is one way to use both legacy and Vim9 syntax in one script file: >
	" comments may go here
	if !has('vim9script')
	   " legacy script commands go here
	   finish
	endif
	vim9script
	# Vim9 script commands go here
This allows for writing a script that takes advantage of the Vim9 script
syntax if possible, but will also work on a Vim version without it.

This can only work in two ways:
1. The "if" statement evaluates to false, the commands up to `endif` are
   skipped and `vim9script` is then the first command actually executed.
2. The "if" statement evaluates to true, the commands up to `endif` are
   executed and `finish` bails out before reaching `vim9script`.


Export ~
							*:export* *:exp*
Exporting an item can be written as: >
	export const EXPORTED_CONST = 1234
	export var someValue = ...
	export final someValue = ...
	export const someValue = ...
	export def MyFunc() ...
	export class MyClass ...
	export interface MyClass ...
<							*E1043* *E1044*
As this suggests, only constants, variables, `:def` functions and classes can
be exported. {not implemented yet: class, interface}

							*E1042*
`:export` can only be used in Vim9 script, at the script level.


Import ~
					*:import* *:imp* *E1094* *E1047* *E1262*
					*E1048* *E1049* *E1053* *E1071* *E1236*
The exported items can be imported in another Vim9 script: >
	import "myscript.vim"

This makes each item available as "myscript.item".
						*:import-as* *E1257* *E1261*
In case the name is long or ambiguous, another name can be specified: >
	import "thatscript.vim" as that
<						*E1060* *E1258* *E1259* *E1260*
Then you can use "that.EXPORTED_CONST", "that.someValue", etc.  You are free
to choose the name "that".  Use something that will be recognized as referring
to the imported script.  Avoid command names, command modifiers and builtin
function names, because the name will shadow them.
If the name starts with a capital letter it can also shadow global user
commands and functions.  Also, you cannot use the name for something else in
the script, such as a function or variable name.

In case the dot in the name is undesired, a local reference can be made for a
function: >
	var LongFunc = that.LongFuncName

This also works for constants: >
	const MAXLEN = that.MAX_LEN_OF_NAME

This does not work for variables, since the value would be copied once and
when changing the variable the copy will change, not the original variable.
You will need to use the full name, with the dot.

The full syntax of the command is:
	import {filename} [as {name}]
Where {filename} is an expression that must evaluate to a string.  Without the
"as {name}" part it must end in ".vim".  {name} must consist of letters,
digits and '_', like |internal-variables|.

`:import` can also be used in legacy Vim script.  The imported items still
become script-local, even when the "s:" prefix is not given.

`:import` can not be used in a function.  Imported items are intended to exist
at the script level and only imported once.

The script name after `import` can be:
- A relative path, starting "." or "..".  This finds a file relative to the
  location of the script file itself.  This is useful to split up a large
  plugin into several files.
- An absolute path, starting with "/" on Unix or "D:/" on MS-Windows.  This
  will rarely be used.
- A path not being relative or absolute.  This will be found in the
  "import" subdirectories of 'runtimepath' entries.  The name will usually be
  longer and unique, to avoid loading the wrong file.
  Note that "after/import" is not used.

If the name does not end in ".vim" then the use of "as name" is required.

Once a vim9 script file has been imported, the result is cached and used the
next time the same script is imported.  It will not be read again.

It is not allowed to import the same script twice, also when using two
different "as" names.

When using the imported name the dot and the item name must be in the same
line, there can be no line break: >
	echo that.
		name   # Error!
	echo that
		.name  # Error!
<							*:import-cycle*
The `import` commands are executed when encountered.  If script A imports
script B, and B (directly or indirectly) imports A, this will be skipped over.
At this point items in A after "import B" will not have been processed and
defined yet.  Therefore cyclic imports can exist and not result in an error
directly, but may result in an error for items in A after "import B" not being
defined.  This does not apply to autoload imports, see the next section.


Importing an autoload script ~
							*vim9-autoload*
For optimal startup speed, loading scripts should be postponed until they are
actually needed.  Using the autoload mechanism is recommended:
							*E1264*
1. In the plugin define user commands, functions and/or mappings that refer to
   items imported from an autoload script. >
	import autoload 'for/search.vim'
	command -nargs=1 SearchForStuff search.Stuff(<f-args>)

<   This goes in .../plugin/anyname.vim.  "anyname.vim" can be freely chosen.
   The "SearchForStuff" command is now available to the user.

   The "autoload" argument to `:import` means that the script is not loaded
   until one of the items is actually used.  The script will be found under
   the "autoload" directory in 'runtimepath' instead of the "import"
   directory.

2. In the autoload script put the bulk of the code. >
	vim9script
	export def Stuff(arg: string)
	  ...

<   This goes in .../autoload/for/search.vim.

   Putting the "search.vim" script under the "/autoload/for/" directory has
   the effect that "for#search#" will be prefixed to every exported item.  The
   prefix is obtained from the file name, as you would to manually in a
   legacy autoload script.  Thus the exported function can be found with
   "for#search#Stuff", but you would normally use `import autoload` and not
   use the prefix (which has the side effect of loading the autoload script
   when compiling a function that encounters this name).

   You can split up the functionality and import other scripts from the
   autoload script as you like.  This way you can share code between plugins.

For defining a mapping that uses the imported autoload script the special key
|<ScriptCmd>| is useful.  It allows for a command in a mapping to use the
script context of where the mapping was defined.

When compiling a `:def` function and a function in an autoload script is
encountered, the script is not loaded until the `:def` function is called.
This also means you get any errors only at runtime, since the argument and
return types are not known yet.  If you would use the name with '#' characters
then the autoload script IS loaded.

Be careful to not refer to an item in an autoload script that does trigger
loading it unintentionally.  For example, when setting an option that takes a
function name, make sure to use a string, not a function reference: >
	import autoload 'qftf.vim'
	&quickfixtextfunc = 'qftf.Func'  # autoload script NOT loaded
	&quickfixtextfunc = qftf.Func    # autoload script IS loaded
On the other hand, it can be useful to load the script early, at a time when
any errors should be given.

For testing the |test_override()| function can be used to have the
`import autoload` load the script right away, so that the items and types can
be checked without waiting for them to be actually used: >
	test_override('autoload', 1)
Reset it later with: >
	test_override('autoload', 0)
Or: >
	test_override('ALL', 0)


Import in legacy Vim script ~

If an `import` statement is used in legacy Vim script, the script-local "s:"
namespace will be used for the imported items, even when "s:" is not
specified.


==============================================================================

6. Future work: classes					*vim9-classes*

Above "class" was mentioned a few times, but it has not been implemented yet.
Most of Vim9 script can be created without this functionality, and since
implementing classes is going to be a lot of work, it is left for the future.
For now we'll just make sure classes can be added later.

Thoughts:
- `class` / `endclass`, the whole class must be in one file
- Class names are always CamelCase (to avoid a name clash with builtin types)
- A single constructor called "constructor"
- Single inheritance with `class ThisClass extends BaseClass`
- `abstract class` (class with incomplete implementation)
- `interface` / `endinterface` (abstract class without any implementation)
- `class SomeClass implements SomeInterface`
- Generics for class: `class <Tkey, Tentry>`
- Generics for function: `def <Tkey> GetLast(key: Tkey)`

Again, much of this is from TypeScript with a slightly different syntax.

Some things that look like good additions:
- Use a class as an interface (like Dart)
- Extend a class with methods, using an import (like Dart)
- Mixins
- For testing: Mock mechanism

An important class that will be provided is "Promise".  Since Vim is single
threaded, connecting asynchronous operations is a natural way of allowing
plugins to do their work without blocking the user.  It's a uniform way to
invoke callbacks and handle timeouts and errors.

Some commands have already been reserved:
	*:class*
	*:endclass*
	*:abstract*
	*:enum*
	*:endenum*
	*:interface*
	*:endinterface*
	*:static*
	*:type*

Some examples: >

	abstract class Person 
	    static const prefix = 'xxx'
	    var name: string
	    
	    def constructor(name: string)
		this.name = name
	    enddef

	    def display(): void
		echo name
	    enddef

	    abstract def find(string): Person
	endclass

==============================================================================

9. Rationale						*vim9-rationale*

The :def command ~

Plugin writers have asked for much faster Vim script.  Investigations have
shown that keeping the existing semantics of function calls make this close to
impossible, because of the overhead involved with calling a function, setting
up the local function scope and executing lines.  There are many details that
need to be handled, such as error messages and exceptions.  The need to create
a dictionary for a: and l: scopes, the a:000 list and several others add too
much overhead that cannot be avoided.

Therefore the `:def` method to define a new-style function had to be added,
which allows for a function with different semantics.  Most things still work
as before, but some parts do not.  A new way to define a function was
considered the best way to separate the legacy style code from Vim9 style code.

Using "def" to define a function comes from Python. Other languages use
"function" which clashes with legacy Vim script.


Type checking ~

When compiling lines of Vim commands into instructions as much as possible
should be done at compile time.  Postponing it to runtime makes the execution
slower and means mistakes are found only later.  For example, when
encountering the "+" character and compiling this into a generic add
instruction, at runtime the instruction would have to inspect the type of the
arguments and decide what kind of addition to do.  And when the type is
dictionary throw an error.  If the types are known to be numbers then an "add
number" instruction can be used, which is faster.  The error can be given at
compile time, no error handling is needed at runtime, since adding two numbers
cannot fail.

The syntax for types, using <type> for compound types, is similar to Java.  It
is easy to understand and widely used.  The type names are what were used in
Vim before, with some additions such as "void" and "bool".


Removing clutter and weirdness ~

Once decided that `:def` functions have different syntax than legacy functions,
we are free to add improvements to make the code more familiar for users who
know popular programming languages.  In other words: remove weird things that
only Vim does.

We can also remove clutter, mainly things that were done to make Vim script
backwards compatible with the good old Vi commands.

Examples:
- Drop `:call` for calling a function and `:eval` for manipulating data.
- Drop using a leading backslash for line continuation, automatically figure
  out where an expression ends.

However, this does require that some things need to change:
- Comments start with # instead of ", to avoid confusing them with strings.
  This is good anyway, it is known from several popular languages.
- Ex command ranges need to be prefixed with a colon, to avoid confusion with
  expressions (single quote can be a string or a mark, "/" can be divide or a
  search command, etc.).

Goal is to limit the differences.  A good criteria is that when the old syntax
is accidentally used you are very likely to get an error message.


Syntax and semantics from popular languages ~

Script writers have complained that the Vim script syntax is unexpectedly
different from what they are used to.  To reduce this complaint popular
languages are used as an example.  At the same time, we do not want to abandon
the well-known parts of legacy Vim script.

For many things TypeScript is followed.  It's a recent language that is
gaining popularity and has similarities with Vim script.  It also has a
mix of static typing (a variable always has a known value type) and dynamic
typing (a variable can have different types, this changes at runtime).  Since
legacy Vim script is dynamically typed and a lot of existing functionality
(esp. builtin functions) depends on that, while static typing allows for much
faster execution, we need to have this mix in Vim9 script.

There is no intention to completely match TypeScript syntax and semantics.  We
just want to take those parts that we can use for Vim and we expect Vim users
will be happy with.  TypeScript is a complex language with its own history,
advantages and disadvantages.  To get an idea of the disadvantages read the
book: "JavaScript: The Good Parts".  Or find the article "TypeScript: the good
parts" and read the "Things to avoid" section.

People familiar with other languages (Java, Python, etc.) will also find
things in TypeScript that they do not like or do not understand.  We'll try to
avoid those things.

Specific items from TypeScript we avoid:
- Overloading "+", using it both for addition and string concatenation.  This
  goes against legacy Vim script and often leads to mistakes.  For that reason
  we will keep using ".." for string concatenation.  Lua also uses ".." this
  way.  And it allows for conversion to string for more values.
- TypeScript can use an expression like "99 || 'yes'" in a condition, but
  cannot assign the value to a boolean.  That is inconsistent and can be
  annoying.  Vim recognizes an expression with && or || and allows using the
  result as a bool.  The |falsy-operator| was added for the mechanism to use a
  default value.
- TypeScript considers an empty string as Falsy, but an empty list or dict as
  Truthy.  That is inconsistent.  In Vim an empty list and dict are also
  Falsy.
- TypeScript has various "Readonly" types, which have limited usefulness,
  since a type cast can remove the immutable nature.  Vim locks the value,
  which is more flexible, but is only checked at runtime.
- TypeScript has a complicated "import" statement that does not match how the
  Vim import mechanism works.  A much simpler mechanism is used instead, which
  matches that the imported script is only sourced once.


Declarations ~

Legacy Vim script uses `:let` for every assignment, while in Vim9 declarations
are used.  That is different, thus it's good to use a different command:
`:var`.  This is used in many languages.  The semantics might be slightly
different, but it's easily recognized as a declaration.

Using `:const`  for constants is common, but the semantics varies.  Some
languages only make the variable immutable, others also make the value
immutable.  Since "final" is well known from Java for only making the variable
immutable we decided to use that.  And then `:const` can be used for making
both immutable.  This was also used in legacy Vim script and the meaning is
almost the same.

What we end up with is very similar to Dart: >
	:var name	# mutable variable and value
	:final name	# immutable variable, mutable value
	:const name	# immutable variable and value

Since legacy and Vim9 script will be mixed and global variables will be
shared, optional type checking is desirable.  Also, type inference will avoid
the need for specifying the type in many cases.  The TypeScript syntax fits
best for adding types to declarations: >
	var name: string	  # string type is specified
	...
	name = 'John'
	const greeting = 'hello'  # string type is inferred

This is how we put types in a declaration: >
	var mylist: list<string>
	final mylist: list<string> = ['foo']
	def Func(arg1: number, arg2: string): bool

Two alternatives were considered:
1. Put the type before the name, like Dart: >
	var list<string> mylist
	final list<string> mylist = ['foo']
	def Func(number arg1, string arg2) bool
2. Put the type after the variable name, but do not use a colon, like Go: >
	var mylist list<string>
	final mylist list<string> = ['foo']
	def Func(arg1 number, arg2 string) bool

The first is more familiar for anyone used to C or Java.  The second one
doesn't really have an advantage over the first, so let's discard the second.

Since we use type inference the type can be left out when it can be inferred
from the value.  This means that after `var` we don't know if a type or a name
follows.  That makes parsing harder, not only for Vim but also for humans.
Also, it will not be allowed to use a variable name that could be a type name,
using `var string string` is too confusing.

The chosen syntax, using a colon to separate the name from the type, adds
punctuation, but it actually makes it easier to recognize the parts of a
declaration.


Expressions ~

Expression evaluation was already close to what other languages are doing.
Some details are unexpected and can be improved.  For example a boolean
condition would accept a string, convert it to a number and check if the
number is non-zero.  This is unexpected and often leads to mistakes, since
text not starting with a number would be converted to zero, which is
considered false.  Thus using a string for a condition would often not give an
error and be considered false.  That is confusing.

In Vim9 type checking is stricter to avoid mistakes.  Where a condition is
used, e.g. with the `:if` command and the `||` operator, only boolean-like
values are accepted:
	true:  `true`, `v:true`, `1`, `0 < 9`
	false: `false`, `v:false`, `0`, `0 > 9`
Note that the number zero is false and the number one is true.  This is more
permissive than most other languages.  It was done because many builtin
functions return these values.

If you have any type of value and want to use it as a boolean, use the `!!`
operator:
	true: `!!'text'`, `!![99]`, `!!{'x': 1}`, `!!99`
	false: `!!''`, `!![]`, `!!{}`

From a language like JavaScript we have this handy construct: >
	GetName() || 'unknown'
However, this conflicts with only allowing a boolean for a condition.
Therefore the "??" operator was added: >
	GetName() ?? 'unknown'
Here you can explicitly express your intention to use the value as-is and not
result in a boolean. This is called the |falsy-operator|.


Import and Export ~

A problem of legacy Vim script is that by default all functions and variables
are global.  It is possible to make them script-local, but then they are not
available in other scripts.  This defies the concept of a package that only
exports selected items and keeps the rest local.

In Vim9 script a mechanism very similar to the JavaScript import and export
mechanism is supported.  It is a variant to the existing `:source` command
that works like one would expect:
- Instead of making everything global by default, everything is script-local,
  unless exported.
- When importing a script the symbols that are imported are explicitly listed,
  avoiding name conflicts and failures if functionality is added later.
- The mechanism allows for writing a big, long script with a very clear API:
  the exported function(s) and class(es).
- By using relative paths loading can be much faster for an import inside of a
  package, no need to search many directories.
- Once an import has been used, it can be cached and loading it again can be
  avoided.
- The Vim-specific use of "s:" to make things script-local can be dropped.

When sourcing a Vim9 script from a legacy script, only the items defined
globally can be used, not the exported items.  Alternatives considered:
- All the exported items become available as script-local items.  This makes
  it uncontrollable what items get defined and likely soon leads to trouble.
- Use the exported items and make them global.  Disadvantage is that it's then
  not possible to avoid name clashes in the global namespace.
- Completely disallow sourcing a Vim9 script, require using `:import`.  That
  makes it difficult to use scripts for testing, or sourcing them from the
  command line to try them out.
Note that you can also use `:import` in legacy Vim script, see above.


Compiling functions early ~

Functions are compiled when called or when `:defcompile` is used.  Why not
compile them early, so that syntax and type errors are reported early?

The functions can't be compiled right away when encountered, because there may
be forward references to functions defined later.  Consider defining functions
A, B and C, where A calls B, B calls C, and C calls A again.  It's impossible
to reorder the functions to avoid forward references.

An alternative would be to first scan through the file to locate items and
figure out their type, so that forward references are found, and only then
execute the script and compile the functions.  This means the script has to be
parsed twice, which is slower, and some conditions at the script level, such
as checking if a feature is supported, are hard to use.  An attempt was made
to see if it works, but it turned out to be impossible to make work nicely.

It would be possible to compile all the functions at the end of the script.
The drawback is that if a function never gets called, the overhead of
compiling it counts anyway.  Since startup speed is very important, in most
cases it's better to do it later and accept that syntax and type errors are
only reported then.  In case these errors should be found early, e.g. when
testing, the `:defcompile` command will help out.


Why not use an embedded language? ~

Vim supports interfaces to Perl, Python, Lua, Tcl and a few others.  But
these interfaces have never become widely used, for various reasons.  When
Vim9 was designed a decision was made to make these interfaces lower priority
and concentrate on Vim script.

Still, plugin writers may find other languages more familiar, want to use
existing libraries or see a performance benefit.  We encourage plugin authors
to write code in any language and run it as an external tool, using jobs and
channels.  We can try to make this easier somehow.

Using an external tool also has disadvantages.  An alternative is to convert
the tool into Vim script.  For that to be possible without too much
translation, and keeping the code fast at the same time, the constructs of the
tool need to be supported.  Since most languages support classes the lack of
support for classes in Vim is then a problem.


Classes ~

Vim supports a kind-of object oriented programming by adding methods to a
dictionary.  With some care this can be made to work, but it does not look
like real classes.  On top of that, it's quite slow, because of the use of
dictionaries.

The support of classes in Vim9 script is a "minimal common functionality" of
class support in most languages.  It works much like Java, which is the most
popular programming language.



 vim:tw=78:ts=8:noet:ft=help:norl:
