Nelua オーバービュー 型・関数


本家様

ここからの抜粋&翻訳
Luaとの違いがある場合はそちらも併記します.
ざっくりと簡単な部分だけ導入しておきます.

プリミティブ

bool, string型はLuaと変わりありません.

数値型

array.nelua
local dec = 1234 -- variable of type 'integer'
local bin = 0b1010 -- variable of type 'uint8', set from binary number
local hex = 0xff -- variable of type 'integer', set from hexadecimal number
local char = 'A'_u8 -- variable of type 'uint8' set from ASCII character
local exp = 1.2e-100 -- variable of type 'number' set using scientific notation
local frac = 1.41 -- variable of type 'number'
print(dec,bin,hex,char,exp,frac)

local pi = 0x1.921FB54442D18p+1 -- hexadecimal with fractional and exponent
print(pi) -- outputs: 3.1415926535898

local a = 1234_u32 -- variable of type 'int32'
local b = 1_f32 -- variable of type 'float32'
local c = -1_isize -- variable of type `isize`
print(a,b,c) --outputs: 1234 1.0 -1

バイナリー型,アスキー文字形式への対応のほか,サフィックスで型を指定できるようになりました

配列

array.nelua
local a: [4]integer = {1,2,3,4}
print(a[0], a[1], a[2], a[3]) -- outputs: 1 2 3 4

local b: [4]integer
print(b[0], b[1], b[2], b[3]) -- outputs: 0 0 0 0
local len = #b -- get the length of the array, should be 4
print(len) -- outputs: 4

コンパイル時に配列のサイズを確定させることができるようになったのは大きいです.また,配列のサイズは指定しなくとも推論されます.

列挙型

enum.nelua
require 'traits'
local Weeks = @enum{
  Sunday = 0,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
}
print(Weeks.Sunday) -- outputs: 0

local a: Weeks = Weeks.Monday
print(a) -- outputs: 1
print(type(a)) -- outputs: number

switch同様実装された模様.とはいえtostringもtypeにも対応していないのは何も変わっていないように見える.自作Enumなどなくとも,型注釈含め,コードの可読性向上に貢献してくれるかどうかといったところ.

レコード型

record.nelua
local Person = @record{
  name: string,
  age: integer
}

-- typed initialization
local a: Person = {name = "Mark", age = 20}
print(a.name, a.age)

-- casting initialization
local b = (@Person){name = "Paul", age = 21}
print(b.name, b.age)

-- ordered fields initialization
local c = (@Person){"Eric", 21}
print(c.name, c.age)

-- late initialization
local d: Person
d.name = "John"
d.age  = 22
print(d.name, d.age)

Luaではテーブル型に強引に要素を追加する形で表現されていた.@recordキーワードがなければエラーになるほか,typeはrecordと判定される.

ユニオン型

union.nelua
local IntOrFloat = @union{
  i: int64,
  f: float64,
}
local u: IntOrFloat = {i=1}
print(u.i) -- outputs: 1
u.f = 1
print(u.f) -- outputs: 1.0f
print(u.i) -- outputs some garbage integer

新規構文.Cでの共用型に相当し,上記コードから分かるように,Unionの中で有効な値は一つのみで,それ以外はGCによって回収されている

ポインター

pointer.nelua
local n = nilptr -- a generic pointer, initialized to nilptr
local p: pointer -- a generic pointer to anything, initialized to nilptr
local i: *integer -- pointer to an integer
local a: integer = 10
i = &a
print(i) -- 適当なメモリの値

新規構文.もともとのLuaの用途的にポインタが必要になる場面がそんなにあるのか?

関数ポインタ

functional_pointer.nelua
local function add_impl(x: integer, y: integer): integer
  return x + y
end

local function double_add_impl(x: integer, y: integer): integer
  return 2*(x + y)
end

local add: function(x: integer, y: integer): integer
add = add_impl
print(add(1,2)) -- outputs 3
add = double_add_impl
print(add(1,2)) -- outputs 6

Luaでも元からできていたことではあるが,特に型注釈をつけられるようになった恩恵が大きい.

Type型

mytype.nelua
local MyInt: type = @integer -- a symbol of type 'type' holding the type 'integer'
local a: MyInt -- variable of type 'MyInt' (actually an 'integer')
print(a) -- outputs: 0

いわゆるエイリアス.

明示的な型変換

explicit_cast.nelua
local i = 1
local f = (@number)(i) -- convert 'i' to the type 'number'
print(i, f) -- outputs: 1 1.0

local MyNumber = @number
local i = 1
local f = MyNumber(i) -- convert 'i' to the type 'number'
print(i, f) -- outputs: 1 1.0

local ni: integer = -1
-- the following would crash with "narrow casting from int64 to uint64 failed"
--local nu: uinteger = ni

local nu: uinteger = (@uinteger)(ni) -- explicit cast works, no checks are done
print(nu) -- outputs: 18446744073709551615

オペレーター

以下のオペレーターが追加されました.
+ /// %%% : 商を0に丸めます.
+ >>> : 算術右シフトを計算します.
+ $ : メモリが参照している値を出します.
+ & : メモリを参照します.

関数

戻り値の推論

return_type.nelua
local function add(a: integer, b: integer)
  return a + b -- return is of deduced type 'integer'
end
print(add(1, 2)) -- outputs 

再帰関数の場合は,戻り値の推論ができないので明示的に指定する必要があります.

複数の戻り値

multiple_return.nelua
local function get_multiple(): (boolean, integer)
  return false, 1
end

local a, b = get_multiple()
print(a,b) -- outputs: false 1

無名関数

lambda.nelua
local z = function(x: integer):integer return x + 10 end
print(z(10))

型注釈がつけられるようになった

ポリモーフィック関数

polymorphic.nelua
local function add(a: auto, b: auto)
  return a + b
end

local a = add(1,2)
-- call to 'add', a function 'add(a: integer, b: integer): integer' is defined
print(a) -- outputs: 3
local b = add(1.0, 2.0)
-- call to 'add' with different types, function 'add(a: number, b: number): number' is defined
print(b) -- outputs: 3.0
print(add(1, 'b')) -- compile time error!

+オペレーターに対応しない値を渡してもコンパイルエラーにはならず,ランタイムで落ちます.プリプロセッサーを使用することでそれを防ぐことができます.

preprocess_add.nelua
local function preprocess_add(a: auto, b:auto)
## static_assert(a.type.is_scalar, 'a is not a number. type "%s"', a.type)
## static_assert(b.type.is_scalar, 'b is not a number. type "%s"', b.type)
    return a + b
end

詳しくは Concepts

レコード型の関数

record_function.nelua
local Vec2 = @record{x: number, y: number}

function Vec2.create(x: integer, y: integer): Vec2
  return (@Vec2){x, y}
end

local v = Vec2.create(1,2)
print(v.x, v.y) -- outputs: 1.0 2.0
record_function.nelua
local Rect = @record{x: number, y: number, w: number, h: number}

function Rect:translate(x: number, y: number)
  -- 'self' here is of the type '*Rect'
  self.x = self.x + x
  self.y = self.y + y
end

function Rect:area()
  -- 'self' here is of the type '*Rect'
  return self.w * self.h
end

local v = Rect{0,0,2,3}
v:translate(2,2)
print(v.x, v.y) -- outputs: 2.0 2.0
print(v:area()) -- outputs: 6.0

examples/record_inheretance.nelua が詳しい