ชนิดของค่า (Value Types)
WebAssembly เป็น stack machine แบบมีชนิด (typed) ค่าทุกตัวบน stack มีชนิดที่ชัดเจน และฟังก์ชันทุกตัวประกาศอย่างแน่ชัดว่ารับและผลิตชนิดใดบ้าง แต่ต่างจากภาษาส่วนใหญ่ Wasm มีชุดของชนิดให้เลือกที่เล็กมาก
ชนิดของค่าทั้งสี่
หัวข้อที่มีชื่อว่า “ชนิดของค่าทั้งสี่”WebAssembly มีชนิดของค่าทั้งหมดสี่ชนิดพอดี:
| Type | Width | Kind |
|---|---|---|
i32 | 32-bit | Integer |
i64 | 64-bit | Integer |
f32 | 32-bit | Float |
f64 | 64-bit | Float |
ในระดับ Wasm ไม่มีสตริง บูลีน อาเรย์ หรืออ็อบเจกต์ ทุกอย่างเป็นตัวเลข ตรรกะแบบบูลีนถูกแทนด้วยค่า i32 โดยที่ 0 หมายถึง false และค่าใด ๆ ที่ไม่ใช่ศูนย์หมายถึง true
การ push ค่าคงที่ขึ้นไปบน stack
หัวข้อที่มีชื่อว่า “การ push ค่าคงที่ขึ้นไปบน stack”แต่ละชนิดมีคำสั่ง const ที่ push ค่าลิเทอรัล:
(module (func (export "answer") (result i32) i32.const 42))สำหรับ float 64 บิต:
(module (func (export "pi") (result f64) f64.const 3.14159265358979))และสำหรับจำนวนเต็ม 64 บิต — สังเกตว่า i64 มีความพิเศษเมื่อข้ามไปยัง JavaScript:
(module (func (export "bignum") (result i64) i64.const 1000000000000))i64 กับ BigInt ของ JavaScript
หัวข้อที่มีชื่อว่า “i64 กับ BigInt ของ JavaScript”ชนิด number ของ JavaScript เป็น float 64 บิต ซึ่งสามารถแทนจำนวนเต็มได้อย่างแม่นยำถึง 2^53 เท่านั้น แต่ i64 สามารถเก็บค่าที่เกินกว่านั้นไปไกลมาก เพื่อรักษาความแม่นยำเต็มที่ WebAssembly JavaScript API จะแปลงค่าที่คืนกลับชนิด i64 ให้เป็น BigInt แทนที่จะเป็น number นั่นหมายความว่า typeof result === 'bigint' — ไม่ใช่ 'number'
คุณสามารถตรวจสอบสิ่งนี้ได้ใน runner ด้านล่าง
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| เขียน WAT เอง | เห็นชัดว่าทุกค่าบน stack มีชนิดกำกับตายตัว (i32, i64, f32, f64) ช่วยให้เข้าใจ type system ของ Wasm อย่างละเอียด | ต้องเลือก const/instruction ให้ตรงชนิดเองทุกครั้ง ผิดชนิดแล้ว validation ไม่ผ่านทันที |
| ปล่อยให้ compiler generate Wasm (Rust/AssemblyScript) | compiler แปลงชนิดจากภาษาต้นทางไปเป็น i32/i64/f32/f64 ให้อัตโนมัติ ลดโอกาสพลาดเรื่อง type | ต้องเชื่อใจ compiler ในการแปลงชนิด เช่น i64 เป็น BigInt โดยไม่รู้รายละเอียดว่าเกิดอะไรขึ้นตรงกลาง |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- push ค่าด้วย instruction ผิดชนิด เช่นใช้
i32.constตอนที่ฟังก์ชันประกาศ(result i64)ทำให้ค่าที่ค้างอยู่บน stack ตอนจบฟังก์ชันมีชนิดไม่ตรงกับ signature และ validation ไม่ผ่าน - สลับลำดับ operand ตอน push ค่าคงที่ขึ้น stack ก่อนเรียกคำสั่งคำนวณ ทำให้ผลลัพธ์ผิดทั้งที่ทุกค่าที่ push มีชนิดถูกต้องแล้ว
- ลืมว่าฝั่ง JavaScript ต้องรับค่า
i64เป็นBigIntไม่ใช่numberแล้วเอาไปเปรียบเทียบหรือคำนวณต่อแบบ mix กับ number ตรง ๆ ทำให้เกิด TypeError ตอน runtime
💡 ตัวอย่างจากของจริง
ชุด test suite ของ WABT (WebAssembly Binary Toolkit) มีไฟล์
.watที่เขียนมือจำนวนมากซึ่งครอบคลุมทุกชนิดค่า (i32,i64,f32,f64) เพื่อยืนยันว่า encoder/decoder ตีความแต่ละชนิดตรงตาม spec รวมถึงกรณีi64ที่ฝั่ง JavaScript ต้องแปลงเป็นBigInt