โครงการ Chromium ที่เป็นโครงการต้นน้ำของเบราว์เซอร์ Chrome ประกาศเริ่มรองรับไลบรารีภาษา Rust เป็นจุดเริ่มต้นของการใช้ภาษา Rust เพื่อเพิ่มความปลอดภัยให้ซอฟต์แวร์โดยรวม
การใช้งานช่วงแรกจะเป็นการใช้งานทางเดียว นั่นคือตัวโค้ด Chromium หลักที่เป็น C++ จะเรียกไลบรารีที่เป็นภาษา Rust ได้แต่ไลบรารีเหล่านั้นห้ามเรียกโค้ด C++ อื่นอีก และโค้ด Rust ที่ใช้งานจะเป็นส่วนประกอบที่แยกเฉพาะทาง (standalone components) เท่านั้น ไม่ใช่ส่วนที่เป็นแกนหลักของตัวเบราว์เซอร์ โดยทั่วไปไลบรารีเหล่านี้มักรับผิดชอบงานเฉพาะทางเท่านั้น
การใช้งานโค้ด Rust มากกว่านี้จะต้องมีการปรับโครงสร้างค่อนข้างมาก เพราะภาษา Rust สามารถจัดการหน่วยความจำโดยไม่ต้องการ garbage collector ได้เพราะแนวคิดสองอย่าง ได้แก่ อายุของตัวแปร (lifetime) และความเป็นเจ้าของ (exclusive mutability) แต่ในโครงสร้างของเบราว์เซอร์ Chrome นั้นมี pointer ที่ชี้ไปยังออปเจกต์เดียวกันหลายจุดและแก้ไขข้อมูลได้จากหลายส่วนพันกันไปมา การปรับโครงสร้างโค้ด C++ ให้ทำงานเข้ากับภาษา Rust ได้จึงเป็นการปรับโครงสร้างขนานใหญ่ ตอนนี้เองกูเกิลก็ลงทุนพัฒนา โครงการอย่าง Crubit ที่เชื่อมภาษา C++ เข้ากับ Rust ได้สองทางอยู่ แต่ก็ยังเป็นโครงการระดับทดลองเท่านั้น
ที่มา - Google Security Blog
Comments
เพราะแนวคิดสองอย่าง อื่น ?
หลาย ๆ ทีมมองไกลไปถึงขั้นย้ายภาษา ซึ่งคิดว่ามีความเสี่ยงเหมือนกัน (แต่ไม่เสี่ยงเท่า Servo ที่เล่นเขียนใหม่หมดทุกอย่างเลยยังติดอยู่ในตมอยู่จนถึงตอนนี้) ผมก็ยังมองว่า เอ... ลองเริ่มจาก modernize codebase ก่อนมั้ย ?
C++ ในปัจจุบันเอง ก็มีเรื่อง object lifetime เหมือนกัน (stack-base, smart pointer, etc.) แต่ถ้าคนเขียนยังคิดว่า เฮ้ถ้าก๊อปปี้เยอะ ๆ มันจะช้านะ หรือ เอ พอใช้ unique pointer เยอะ ๆ แล้วมันน่ารำคาญ (เพราะต้องคอยสร้าง weak pointer เวลาส่งให้คนอื่นใช้)
ส่วนเรื่อง mutability ผมว่าไม่ใช่เรื่องใหม่ แต่คนก็รำคาญเหมือนกัน เพราะมันต้องพิมพ์ keyword เพิ่ม ก็เลยแบบลืมพิมพ์บ้างอะไรบ้าง คิดว่าการใช้ static analysis มาช่วยก็น่จะช่วยได้มากพอสมควร
แต่จุดอ่อนของ C++ จริง ๆ น่าจะเป็นการที่มันมีฟีเจอร์มากมาย เพราะเป็นภาษาเก่า แต่ในทางกลับกันฟีเจอร์ที่คนมองหาก็อาจจะไม่มี (เช่น string manipulation ของ C++ นี่ห่วยมากๆ แค่ search string ยังยากเลย) มันก็เลยกลายเป็นภาษาที่เข้าถึงได้ยาก หาคนสานต่อได้ยาก
แต่เอาจริง ก็มีคนเริ่มพูดถึง C++/2 กันแล้ว ตัดฟีเจอร์ที่ไม่ได้ใช้จริง หรือใช้ไม่ได้จริงทิ้งไป (C++ มีฟีเจอร์ที่เคยถูกตัดทิ้งมาก่อนบ้าง เช่น Garbage Collection) แต่ถ้าจะไปขั้นนั้น ไป Rust แทนก็อาจจะดีกว่า (แต่ project governance อาจจะไม่เปิดเผยเท่า C++ ซึ่งเป็นมาตรฐาน ISO อยู่ ณ.ตอนนี้ (ซึ่งเป็นสาเหตุว่าทำไมมันพัฒนาช้าเหมือนกัน))
ณ.จุดนี้ผมว่า Rust ก็เหมือนกับสมัยที่โปรเจคเริ่มเปลี่ยนจาก C ไปเป็น C++ แหละ (แต่รอบนั้นอาจจะทำได้เนียนกว่า เนียนจนกระทั่งบางคนไม่รู้ว่าตัวเองใช้ C++ อยู่ ไม่ใช่ C) แต่สุดท้ายแล้วโปรเจคที่เป็น C ตอนนี้ก็ยังมีอยู่พอสมควร
Servo ไม่ค่อยขยับแล้วจริง แต่ว่า ชิ้นส่วนบางชิ้นของ Servo ก็เข้าไปอยู่ใน Firefox หลายปีแล้วครับ ปูมที่เอามารวมดูจาก Bugzilla ได้ด้วย หรืออ่านจาก โพสต์นี้ ที่เป็น Blog สรุปก็ได้ครับ
ในประเด็นนั้นผมเข้าใจครับ แต่ผมก็อยากให้เห็นว่า บางทีการเล่นสร้างทุกอย่างตั้งแต่ติดลบมันก็ไม่เหมาะกับโปรเจคขนาดใหญ่ครับ (โดยเฉพาะในองค์กรณ์ที่ไม่ได้มีเงินทุนให้เผาเล่นเยอะขนาดนั้น)
ทำทุกอย่างหมดไม่ไหวจริงครับ ซึ่งผมว่าคนที่ทำ Servo ทราบครับ เพราะว่าอย่างน้อยเขาไม่ได้ทำ ทำ JavaScript engine ยังใช้ Gecko เหมือนเดิม แต่ขนาดว่าตัด Gecko ออกแล้วงานมันเยอะเกินไปอยู่ดีครับ และหลายอย่างก็เป็นงานละรายละเอียด ทำนองว่าเขียน C ธรรมดาก็ได้ เช่น การเลือกฟอนท์ตั้งต้นของแต่ละระบบปฏิบัติการ ดังนั้นผมคิดว่าเริ่มทำทีละโมดูลแบบที่ Chrome ทำก็ดีแล้วครับ
พอต้องมาจับ C++ เพิ่งเข้าใจเลยครับว่าฟีเจอร์มันเยอะมากเป็นยังไง และก็จริงที่ฟีเจอร์พื้นฐานของ string ใช้งานยากกว่าภาษาอื่นเยอะ แต่อย่างว่า C++ มีออพชั่นสำหรับตอน compile เยอะมาก
ผมเห็น CPP2 ก็ดูน่าสนใจนะ เหมือนทีมพัฒนามีความตั้งใจที่จะรักษาความเป็น C++ ไว้ในขณะที่โปรแกรมเมอร์ก็ไม่ต้องปวดหัวกับการเรียนรู้ Library จำนวนมหาศาล
..: เรื่อยไป
ลักษณะงานคือถูกห้ามใช้ libboost หรือ Qt แบบนี้หรือเปล่าครับ ?
ใช่ครับ พอดีเป็นการพัฒนาแบบต่อยอดจากระบบที่มีอยู่แล้วอีกที compiler เป็นแบบของเค้าเอง รองรับ ISO C++14 แล้วก็ library หลักจากตัวแพลตฟอร์ม (ลงอะไรเพิ่มไม่ค่อยได้ด้วย เนื่องจาก policy และรันบน Solaris)
ปล. แต่ผมเป็น C++ programmer มือใหม่น่ะครับ เมนจริงๆไม่ใช่ภาษานี้ หลายๆอย่างน่าจะมาจากที่ผมไม่รู้เองด้วยแหละ
..: เรื่อยไป
ท่านอยู่ในสภาพที่น่าเห็นใจครับ ใช้ libboost ไม่ได้ทั้ง ๆ ที่ libboost ก็ใช้กันบน Solaris ได้
[นอกเรื่อง] โปรแกรมด้าน text processing ใช้ C++ กันเยอะครับ จนถึงทุกวันนี้ เท่าที่ผมเคยเห็นมาเกือบทุกโครงการใช้ libboost ครับ ส่วนที่เหลือใช้ Qt เพื่อที่จะได้ใช้ QString
ขอบคุณสำหรับความรู้ครับ
..: เรื่อยไป
case นี้ควรจะใช้ shared pointer นะครับและมันมี idiom case นี้ให้ด้วย https://youtu.be/QGcVXgEVMJg
ส่วน weak pointer + shared pointer เอาไว้ใช้กับ thread handler ส่วนใหญ่ (ใช้แก้ทาง shared pointer ที่เป็น atomic operation ไม่ต้อง increase reference counter)https://stackoverflow.com/a/34302850/5391421
จะว่าไป ถ้าว่าด้วยเรื่อง memory safe C++ น่าจะ safe กว่า Rust ด้วยซ้ำ ถ้าใช้ smart pointer เป็น
ผมเขียน C++ ไม่เป็นได้แค่เขียนเล่น เมื่อ 5 ปีที่แล้วลองทดสอบ unique_ptr ดู ไม่รู้ว่าล้าสมัยไปแล้วหรือเขียนผิดหรือเปล่านะครับ คือลองเขียนให้โปรแกรมใช้ตัวแปรที่โดน move ไปแล้วครับตามด้านล่าง
ปรากฎว่า compile ผ่านครับ แต่รันไม่ได้ซึ่งก็ไม่ควรได้อยู่แล้ว
ในกรณีแบบนี้ Rust compiler จะตรวจให้ได้เลยครับ
อีกกรณีหนึ่งที่ผมคาดว่า C++ ก็น่าจะตรวจเวลา compile ไม่ได้คือในกรณี share mutable variable กันหลาย ๆ thread ซึ่งใน Rust ตรวจให้ได้ครับ
โค้ดดูยากหน่อยอย่างไรลองดูใน gist ได้นะครับ
ใส่ code ใน markdown ใช้
```cpp
// code
```
ครอบครับ เช่น
ผมทำแล้วเลิกแล้วครับย่อหน้าพังครับ # ก็ไม่ใช่อย่างที่อยากให้เป็น ``` ไม่ใช่ markdown engine ทุกตัวจะรู้จักครับเป็น dialect ของ GitHub
ตะกี้ผมลองรันเล่นๆ ด้วย g++ ก็ยัง compile ผ่านแต่รันไม่ได้เหมือนเดิมครับ
เดามั่วๆว่า C++ compiler จะยังไม่ได้เน้นเรื่อง borrow checker มั้ง Rust ที่เน้นตรงนี้
..: เรื่อยไป
ผิดอย่างแรงครับ ไม่มีใครใช้ unique pointer แบบนี้แน่นอนครับ
- ไม่มีค่อยใครใช้ move กับ unique pointer เพราะใน scope เดี๋ยวกันไม่ควรจะมี reference เดียวกันมากกว่า 1
- โคตร rare ที่จะมีคนใช้ raw pointer จาก smart pointer
- unique pointer == ownership concept ของ Rust
- C++ มี life time object แบบ count reference ให้ (น่าจะเป็น share mutable variable คุณว่า) คือ shared pointer ซึ่งค่อนข้างสะดวกเมื่อใช้กับ thread ที่ไม่รู้ว่าจะจบเมื่อไร ผมลองหาใน STD reference ของ Rust แล้วหาไม่เจอ tool แบบนี้
- weak pointer ของ C++ จุดประสงค์หลักเลยคือป้องกัน dangling pointer เป็น feature ของ memory safe อย่างหนึ่ง แต่หลายคนยังไม่เข้าใจกว่าจะใช้เมื่อไร
- ผมบอกไปแล้วจะให้ safe กว่า Rust ต้องใช้ smart pointer เป็นน่ะครับ มันไม่ได้ safe by default
พอมีตัวอย่างไหมครับ ?
https://godbolt.org/z/c8ovcaPW5https://godbolt.org/z/9srGMWfaq
ownership version c++
ผมปกติผมไม่ได้เขียน C++ เป็นปกติ เลย format, ตั้งชื่อแหวกชาวบ้านหน่อยนะครับ
ไม่เป็นไรครับ โครงการ C++ ก็ดูตั้งชื่อจัด format กันหลากหลายอยู่แล้วครับ
ขอบคุณครับ อย่างน้อยก็ทำให้เห็นว่า compiler กันไม่ให้ auto obj2 = obj1 ได้ แต่ยังไม่เข้าใจว่าทำถึงจะ safe กว่า Rust ครับ
เรื่อง shared_ptr กับ atomic ผมไม่เคยลองเลยครับ แต่เท่าที่อ่านมาไม่มีสิ่งที่เหมือนกันเสียทีเดียวใน Rust ครับ แต่ว่ากรณีที่ใช้ reference counting ข้าม thread ปกติก็ใช้ Arc กันครับ หรือถ้ามาการเขียนตัวแปรนั้นด้วยก็ใช้ Arc<Mutex<...>> หรือ Arc<RwLock<...>> ครับ
หลายอย่างที่ผมเคยคิดว่าไม่น่าจะมีใครเขียนออกมาแบบนั้นได้ แต่เอาจริง ๆ ก็เจอ Rust มันมาช่วยป้องกันส่วนนี้ได้ครับ เช่น โค้ดควรจะใช้ Arc<RwLock<...>> แต่ไม่ใช้ compiler ก็จะไม่ให้ผ่าน
ทีแรกผมคิดว่า Rust ไม่มี Object life time แบบ count reference ครับ (มี memory safe feature มากกว่าก็ควร safe กว่า)แต่ Arc ที่คุณบอกล่ะครับคือสิ่งที่ผมหาไม่เจอ โถมองผ่านๆ ผมก็นึกว่า graphic function
ชื่อคล้ายของ Intel; ผมเคยสับสนกับ Rc แบบไม่มี a ด้วยครับ 😅
ขอบคุณสำหรับความรู้ครับ
ว่าแต่คำสั่ง auto นี่ สำหรับมือใหม่ ผมค่อนข้างสับสนว่าควรเริ่มใช้จากจุดไหน ถึงจะทำให้ code อ่านไม่ยากเกินไป เท่าที่อ่านใน SO ส่วนใหญ่ก็จะบอกว่าให้ใช้ในจุดที่เรารู้ได้ง่ายๆว่า object ที่จะสร้างขึ้นเป็น type อะไร ตอนนี้เลยพยายามยังไม่ใช้ไปก่อน
..: เรื่อยไป
ปัญหาของ C++ อย่างหนึ่ง คิดแค่ตอน runtime ไม่พอ ต้องคิดถึง compile time เยอะกว่าภาษาอื่นเพราะมันมี keyword, feature ที่ใช้เฉพาะตอน compile เยอะมาก inline, constexpr, template, ...
auto ก็เป็นหนึ่งในนั้น
ฉะนั้น ถ้าใช้ auto แล้วไม่ error ตอน compile นี้ไม่มีปัญหาครับ ไม่มี overhead ตอน runtime (ถ้าเขียนไปนานๆ จะเจอ typename ยาวเป็นบรรทัด auto ช่วยได้เยอะ)compiler มันจะเดาและ assign type ให้ตอน compile
แต่ต้องระวัง เวลาใช้กับอะไรที่ type มันไม่ชัดเจน อย่าง literal
โอเค ขอบคุณคร้าบบบ
👍👍👍
..: เรื่อยไป