1 คะแนน โดย GN⁺ 2024-09-27 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • High C Compiler สำหรับ FM TOWNS ในปี 1989 ไม่ได้แค่รองรับสภาพแวดล้อม DOS แต่ยังมีฟีเจอร์ภาษาเชิงผู้ใช้หลายอย่างที่หาได้ยากในคอมไพเลอร์ C ยุคนั้น
  • เมื่อใช้ร่วมกับ DOS extender ของ Phar Lap จึงกลายเป็นคอมไพเลอร์ C แบบ 1st-party ของ FM TOWNS ท่ามกลางกระแสการพัฒนาที่ใช้ประโยชน์จาก 80386 แบบ 32 บิตบนสภาพแวดล้อม MS-DOS 16 บิต
  • ขีดล่างใน numeric literal, อาร์กิวเมนต์แบบมีป้ายชื่อ, ช่วงของ case, ฟังก์ชันซ้อน, generator ฯลฯ เป็นฟีเจอร์ที่เข้ามาในมาตรฐาน C/C++ ช้ากว่านั้นมาก หรือบางอย่างก็ยังไม่มีในมาตรฐานจนถึงปัจจุบัน
  • ฟังก์ชันซ้อนให้ “full function value” ในรูปแบบ non-escaping closure ที่ส่งทั้ง function pointer และ context pointer ไปด้วยกัน ทำให้แสดงออกได้มากกว่า function pointer ของ C แบบปกติ
  • generator ถูกทำเป็น syntax sugar บนฟังก์ชันซ้อน ทำงานด้วยโครงสร้างเรียบง่ายที่แปลงเนื้อหาในลูป for ของผู้เรียกให้เป็นฟังก์ชันซ้อน แล้วส่งเป็นอาร์กิวเมนต์ yield

ตำแหน่งของ FM TOWNS และ High C

  • คู่มือคอมไพเลอร์ C จากทศวรรษ 1980 ที่พบในกองหนังสือเกี่ยวกับ FM TOWNS มีส่วนขยายภาษามากกว่าที่คาดไว้
  • การใช้ C และภาษาตระกูลเดียวกันในสภาพแวดล้อมจริงจำเป็นต้องพึ่ง ส่วนขยายของผู้ผลิต มาเป็นเวลานาน
    • ในสภาพแวดล้อมปัจจุบันที่มี GCC, Clang, MSVC เป็นศูนย์กลาง ส่วนขยายมักเน้นไปที่การจัดการเฉพาะแพลตฟอร์มหรือการควบคุมรายละเอียดระดับต่ำ
    • ในทศวรรษ 1980 มีบริษัทขนาดเล็กจำนวนมากกว่าแข่งขันกันให้ถูกนำไปใช้ ทำให้ฟีเจอร์ส่วนขยายหลากหลายกว่าด้วย
  • Phar Lap สร้างหนึ่งใน DOS extender ยุคแรก ๆ ที่ทำให้ใช้ประโยชน์จากโปรเซสเซอร์ 80386 แบบ 32 บิตได้ในสภาพแวดล้อม MS-DOS 16 บิต
  • MetaWare พอร์ต High C Compiler ไปยัง DOS extender SDK ของ Phar Lap ตามคำว่าจ้างของ Phar Lap
  • Fujitsu ผสาน DOS extender ของ Phar Lap เข้ากับ OS ของแพลตฟอร์ม FM TOWNS ที่ใช้ 80386 และ High C จึงกลายเป็นคอมไพเลอร์ C แบบ 1st-party ของแพลตฟอร์มนี้
  • FM TOWNS เปิดตัวในปี 1989 ก่อนที่ C89 ซึ่งเป็นมาตรฐาน ANSI C ฉบับแรกจะได้รับการให้สัตยาบันไม่นาน

ฟีเจอร์อำนวยความสะดวกเล็ก ๆ ที่มาก่อนมาตรฐาน

  • ตัวคั่นขีดล่างใน numeric literal

    • สามารถใส่ ตัวคั่นขีดล่าง ภายในตัวเลขเพื่อให้อ่าน numeric literal ยาว ๆ ได้ง่ายขึ้น
    • C++ นำตัวคั่นด้วยเครื่องหมายอัญประกาศเดี่ยว เช่น 1'000'000 เข้ามาใน C++14
    • C เพิ่งนำฟีเจอร์คล้ายกันเข้ามาใน C23
  • อาร์กิวเมนต์แบบมีป้ายชื่อ

    • สามารถใส่ชื่ออาร์กิวเมนต์ได้สำหรับฟังก์ชันที่มีพารามิเตอร์มาก หรือใช้ชนิดที่ความหมายไม่ชัดเจน ณ จุดเรียกจำนวนมาก เช่น bool
    • อาร์กิวเมนต์แบบมีป้ายชื่อของ High C ทำงานคล้ายฟีเจอร์ยอดนิยมของ Python
      • ป้ายชื่ออาร์กิวเมนต์เป็นทางเลือก
      • หากมีป้ายชื่อ สามารถระบุอาร์กิวเมนต์ในลำดับใดก็ได้ด้วยไวยากรณ์ argumentName => value
      • สามารถผสมอาร์กิวเมนต์ที่ไม่มีป้ายชื่อกับอาร์กิวเมนต์ที่มีป้ายชื่อได้ แต่พารามิเตอร์ทุกตัวของฟังก์ชันต้องมีอาร์กิวเมนต์ที่สอดคล้องกัน
    • C และ C++ มาตรฐานยังไม่มีฟีเจอร์นี้
  • ช่วงของ case

    • มีฟีเจอร์จับคู่ช่วงของค่าในครั้งเดียว เหมือน case low..high ของ Pascal
    • C และ C++ มาตรฐานไม่ได้รับฟีเจอร์นี้เข้ามา

ฟังก์ชันซ้อนและ full function value

  • High C สามารถประกาศ ฟังก์ชันซ้อน ภายในฟังก์ชันได้เหมือน Pascal
  • วิธีการทำงานใกล้เคียงรูปแบบที่สมบูรณ์กว่ามาตรฐาน Pascal หรือส่วนขยายฟังก์ชันซ้อนของ GCC
  • High C ไม่เพียงประกาศฟังก์ชันซ้อนได้ แต่ยังประกาศชนิด full function value ได้ด้วย
    • ต่างจาก function pointer ของ C แบบดั้งเดิม เพราะเก็บ context pointer ร่วมกับ function pointer
    • ช่วยให้ฟังก์ชันซ้อนสามารถตามหาคอนเท็กซ์ที่มัน capture ไว้ได้อีกครั้ง
    • เป็น non-escaping closure ที่อายุการใช้งานไม่ยืดต่อไปหลังฟังก์ชันภายนอก return แล้ว
  • ส่วนขยายฟังก์ชันซ้อนของ GCC เขียนโค้ดที่รันได้ลงบน call stack เพื่อ thunk context pointer เพราะต้องการให้ฟังก์ชันซ้อนถูกอ้างอิงเป็น function pointer ปกติ
    • วิธีนี้นำไปสู่ความเสี่ยงด้านความปลอดภัยอย่างมาก และทำให้หลายแพลตฟอร์มปิดใช้งานฟีเจอร์ดังกล่าวอย่างสมบูรณ์
  • การอ้างอิงฟังก์ชันท้องถิ่นของ High C ใช้ได้เหมือนค่า first-class แต่ไม่ยืดอายุไปถึงหลังฟังก์ชันภายนอก return แล้ว
  • ฟังก์ชันซ้อนยังสามารถ goto ไปยังฟังก์ชันแม่ได้ด้วย
    • ทำให้ทำ non-local exit ออกจากฟังก์ชันซ้อนได้เหมือนบล็อกของ Smalltalk
    • สามารถใช้สิ่งนี้สร้างฟังก์ชันที่ทำงานเหมือน control flow ได้
  • Objective-C ได้ blocks ที่ใช้เป็น escaping closure ได้ในปี 2009 และ C++ นำ lambdas เข้ามาในปี 2011
  • ทั้งสองฟีเจอร์ไม่มีความสามารถด้าน non-local exit
  • C มาตรฐานยังไม่มีฟีเจอร์ฟังก์ชันซ้อนอย่างเป็นทางการ

Generator coroutine

  • MetaWare ให้ความสำคัญกับฟีเจอร์ generator ถึงขั้นจัดไว้ทั้งบทหนึ่ง
  • High C รองรับ generator coroutine สไตล์ Python ใน plain C ตั้งแต่ปี 1989
  • ฟังก์ชัน generator ประกาศด้วยไวยากรณ์ void foo(Arg arguments) -> (Yield yields)
    • ภายในฟังก์ชันสามารถเรียกฟังก์ชันวิเศษ yield(values...) หลายครั้งเพื่อสร้างลำดับของค่า
    • ผู้เรียกวนผ่านค่าที่สร้างขึ้นตามลำดับด้วยไวยากรณ์ลูป for แบบใหม่ในรูป for variable... <- foo(arguments...) do { ... }
  • การทำงานนี้สามารถผสานกับฟังก์ชันซ้อนได้อย่างซับซ้อน
    • ฟังก์ชันซ้อนภายใน generator สามารถ capture การทำงานของ yield จาก generator ภายนอกได้
    • ฟังก์ชันซ้อนสามารถเรียกตัวเองแบบ recursive เพื่อวนผ่านต้นไม้หรือโครงสร้างข้อมูล recursive แล้ว yield ในแต่ละขั้นได้
  • รูปแบบนี้ดูเหมือนเป็นวิธีที่ทำได้ยากใน Python หรือภาษากระแสหลักจำนวนมากที่มี generator coroutine

วิธีทำงานของ generator และความต่างจากภาษามาตรฐาน

  • generator ของ High C ทำงานเป็น syntax sugar บนฟังก์ชันซ้อน โดยไม่ต้องมี runtime ขั้นสูง
  • การประกาศ generator ในรูป void foo(Arg arguments) -> (Yield yields) เทียบเท่ากับการประกาศฟังก์ชันปกติ void foo(void yield(Yield yields)!, Arg arguments)
    • yield เป็นพารามิเตอร์โดยนัยของชนิด “full function value”
    • การเรียก yield(values) ภายในเนื้อหา generator คือการเรียกฟังก์ชันปกติไปยังพารามิเตอร์ฟังก์ชันโดยนัยนี้
  • ฝั่งผู้เรียก เนื้อหาในลูป for จะถูกแปลงเป็นฟังก์ชันซ้อน
    • ฟังก์ชันซ้อนนี้ถูกส่งเป็นอาร์กิวเมนต์ yield ของ generator
    • โครงสร้างเรียบง่ายแต่ได้ผล
  • เพราะฟังก์ชันซ้อนรองรับ non-local exit คำสั่ง break, continue, goto ที่ออกไปนอกเนื้อหาลูป for จึงทำงานด้วยการ goto ไปยังตำแหน่งนอกลูปที่เหมาะสม
  • มีความเป็นไปได้น้อยที่ C มาตรฐานจะพยายามรวมฟีเจอร์แบบนี้เข้ามา
  • C++20 มีฟีเจอร์ coroutine ที่ยืดหยุ่นมากและซับซ้อน โดยอิงจากการแปลง coroutine ณ compile time
    • ดูเหมือนว่าสามารถใช้สิ่งนี้สร้าง generator ได้
    • แต่ผลลัพธ์ที่ได้คงไม่ผสานกับฟังก์ชันท้องถิ่นได้อย่างตรงไปตรงมาเช่นนี้

1 ความคิดเห็น

 
GN⁺ 2024-09-27
ความคิดเห็นบน Hacker News
  • ในปี 2011 เคยรวบรวมเรื่อง for แบบขับเคลื่อนด้วย iterator ไว้แล้ว เป็นหนึ่งในฟีเจอร์ที่ถูกลืมไปนานแล้ว และตอนนั้นยังพูดถึงด้วยว่าถ้ามันเข้าไปอยู่ในมาตรฐาน C++ จะมีหน้าตาอย่างไร
    โชคดีที่ผมมี High C/C++ Language Reference ฉบับภาษาอังกฤษอยู่หนึ่งเล่ม
    http://jdebp.uk./FGA/metaware-iterator-driven-for.html
    http://jdebp.uk./Proposals/metaware-iterator-driven-for.html
    • อยากรู้ว่า break หรือ return ถูกคอมไพล์อย่างไร มันต้องแปลงให้ฟังก์ชัน yield คืนค่าเป็น status code แล้วตรวจที่จุดเรียกหรือเปล่า?
    • นั่นตั้งใจให้เป็นหน้ายิ้มกลับหัวหรือเปล่า?
  • ใน D รวมถึง Das BetterC ก็มีฟีเจอร์เหล่านี้: ขีดล่างใน numeric literal, ช่วงของ case, named arguments, nested functions, static nested functions, ฟีเจอร์ที่คล้าย generator
    ตัวอย่างเช่น สามารถเขียนได้ในรูปแบบ int a = 1_234_567;, case 5 .. case 6:, test(b:3, a:4);
    static nested function จะเข้าถึงตัวแปรใน frame ของฟังก์ชันภายนอกไม่ได้ จึงเกิด error อย่าง Error: static function test.foo.plus cannot access variable i in frame of function test.foo
    ฟีเจอร์ที่คล้าย generator อยู่ที่ https://dlang.org/spec/statement.html#foreach_over_struct_an...
    • ตลอดเวลาที่อ่านบทความนี้ ผมนึกถึง D ตลอดเลย รู้สึกเหมือน Walter Bright น่าจะโผล่มาในคอมเมนต์
    • ผมมองว่า garbage collector ของ D ก็เป็นฟีเจอร์ที่ดีมากเช่นกัน ในโค้ดระดับล่างบางครั้งก็จำเป็นต้องจัดการหน่วยความจำเอง แต่ในทางปฏิบัติมีหลายส่วนที่ไม่ได้สำคัญนัก และ garbage collector ก็ช่วยทำให้งานง่ายขึ้นมาก
      เช่น ถ้าสร้างบริการแคชในหน่วยความจำ ตัวรายการแคชเองควรไม่ให้ garbage collector ติดตามจะดีกว่า เพราะ garbage collector มักไม่รู้รูปแบบการเข้าถึงจริง จึงอาจกลายเป็นตัวขัดขวางได้ แต่ส่วนประกอบอื่น ๆ ส่วนใหญ่ของบริการนั้นกลับเหมาะกับการมี garbage collector มากกว่า
    • มีคำถาม ทำไมคนถึงไม่ชอบแนวคิด nested functions ใน C กันนะ?
      ทำไม named arguments ถึงอยู่ในรูป test(a:4, b:3) ไม่ใช่ test(.a=4, b.=3);?
      แล้วก็สงสัยว่าใน C จะจัดการ first-class types ได้อย่างไร
  • ที่เกี่ยวข้องกัน คอมไพเลอร์ C lcc-win เพิ่ม operator overloading, default function arguments และ function overloading เข้าไป ในเอกสารให้ดูหัวข้อ “generic functions” [1]
    คอมไพเลอร์ C ของ Plan 9 ก็เพิ่ม language extensions หลายอย่าง และบางส่วน เช่น anonymous structs/unions ก็เข้าไปอยู่ในมาตรฐาน C ในภายหลัง ปัจจุบัน GCC รับแฟล็ก -fplan9-extensions [2] และสามารถเปิดใช้ฟีเจอร์ที่ค่อนข้างมีประโยชน์ได้ เช่น การแปลง struct pointer เป็น anonymous field โดยอัตโนมัติในการเรียกฟังก์ชันและการกำหนดค่า
    [1] https://lcc-win32.services.net/C-Tutorial.pdf
    [2] https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
  • อัจฉริยะที่ทำฟีเจอร์เหล่านี้คือใครกันนะ ดูเหมือนในบริษัทนั้นจะมีคนที่มี วิสัยทัศน์ล่วงหน้า มากอยู่
    น่าเสียดายที่มันไม่ได้แพร่หลายไปทั่วโลกและส่งอิทธิพลต่อมาตรฐานภาษา น่าทึ่งที่มีฟีเจอร์แบบนี้มาตั้งนานแล้ว
    Hacker News ก็เคยพูดถึงมาก่อน: https://news.ycombinator.com/item?id=38938402
    มีสำเนา PDF อยู่ที่ไหนสักแห่งไหม?
    • CLU มี iterator หรือก็คือ for loop ที่มี generator และ yield อยู่แล้วตั้งแต่กลางถึงปลายทศวรรษ 1970 [0] ภาษา Icon ในยุคใกล้เคียงกันก็มีฟีเจอร์ generator คล้ายกัน [1] และใช้คำว่า suspend แทน yield เท่าที่รู้ Ada (1983) ก็มีฟีเจอร์แบบนี้ด้วย
      ฟีเจอร์ภาษาเหล่านี้ไม่ได้ไม่เป็นที่รู้จักโดยสิ้นเชิง
      [0] https://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-2...
      [1] https://dl.acm.org/doi/pdf/10.1145/800055.802034
    • บน Bitsavers มีสำเนา คู่มืออ้างอิง HC 1.2 (1985) อยู่
      อธิบายทั้งขีดล่างในตัวเลข, ช่วงของ case, named parameters, nested functions และแม้กระทั่งตัวแปรฟังก์ชันแบบสมบูรณ์
      https://bitsavers.org/pdf/metaware/…
      ให้ดู Appendix A ซึ่งอยู่ก่อนท้ายไฟล์ราว 50 หน้า
    • MetaWare เป็นบริษัทคอมไพเลอร์ที่ผลิตงานมากใน Santa Cruz ช่วงยุค 80–90 ผมชอบสิ่งที่พวกเขาสร้าง และวัฒนธรรมก็น่าสนใจไม่น้อย
      สมัยก่อนตอนเรียนและเขียนโค้ด ผมได้รู้จักผ่านเว็บที่ค่อนข้างน่าสงสัยนิด ๆ
    • ไม่ใช่เรื่องน่าประหลาดใจนัก ถ้าขุดดูคลัง ภาษาโปรแกรมระดับสูง หลังยุค FORTRAN, Lisp, ALGOL, COBOL ก็จะเห็นไอเดียภาษาแบบนี้มากมาย
      แล้วก็จะพบประวัติศาสตร์อันหลากหลายของภาษาโปรแกรมระบบด้วย จะเห็นด้วยว่าการออกแบบ C และ Go คล้ายกันแค่ไหนในแง่ที่เมินสิ่งที่เกิดขึ้นใน ecosystem อื่น ๆ และประสบการณ์ในอดีต
    • น่าเสียดายที่ฟีเจอร์เหล่านี้ดูเหมือนเป็น ฟีเจอร์ใหม่ แทนที่จะเป็นส่วนหนึ่งของรายการฟีเจอร์มาตรฐานที่ภาษาโปรแกรมส่วนใหญ่มีให้

ลิงก์คู่มือคอมไพเลอร์อยู่ที่ https://winworldpc.com/product/metaware-high-c-cpp/33x
PDF คู่มือ C มีข้อความลิขสิทธิ์ปี 2007

  • การส่งครั้งก่อนและคอมเมนต์อยู่ที่นี่: https://news.ycombinator.com/item?id=38938402
    • วันนี้ Joe Groff ขุดเรื่องนี้ขึ้นมาอีกครั้งบน FediVerse เลยดูเหมือนว่ามันจะถูกนำมาโพสต์ที่นี่อีกด้วย
      https://f.duriansoftware.com/@joe/113195961485703110
    • ดูเหมือนผู้เขียนจะเอาเนื้อหาเดียวกันไปโพสต์ใหม่เมื่อวานนี้ที่ URL อื่น แปลกดี
  • ถ้าสงสัยว่าทำไมสตริงลิเทอรัลในตัวอย่างในรูปถึงลงท้ายด้วย ¥n ไม่ใช่ \n ดูเหมือนว่าตัวอย่างโค้ดเหล่านี้จะเขียนด้วย Shift-JIS ใน Shift-JIS ตำแหน่งของ \ ใน ASCII จะเป็น ¥
    • เดิมทีมันคือ JIS Roman [0] ซึ่งเป็นรูปแบบดัดแปลง ASCII ภาษาญี่ปุ่นจากปี 1969 ส่วน Shift-JIS มาเพิ่มการรองรับชุดอักขระแบบสองไบต์ในภายหลังมาก
      [0] https://en.wikipedia.org/wiki/JIS_X_0201
    • ปัญหาคือใน Shift-JIS รหัส ASCII ของแบ็กสแลชยังถูกใช้เป็นไบต์ที่สองของอักขระ 2 ไบต์ด้วย ดังนั้นสตริงลิเทอรัลภาษาญี่ปุ่นใน C จึงอาจทำงานไม่ถูกต้องในบางครั้ง
      สำหรับการใช้งานแบบนี้ EUC-JP ดีกว่า เพราะไม่มีปัญหานี้ ใน Pascal ถ้าใช้คอมเมนต์แบบ (* *) และไม่ใช้คอมเมนต์แบบ { } ก็จะไม่มีปัญหานี้แม้ใช้ Shift-JIS
    • ผู้เขียนไม่ได้ให้ข้อมูลว่าหนังสือเล่มนี้ออกมาเมื่อไร และค้นหาก็ไม่พบข้อมูล แต่ตอนที่หนังสือออกมา น่าจะยังไม่มีมาตรฐาน Shift-JIS
      แทนที่จะเป็นแบบนั้น มีความเป็นไปได้สูงว่ามีการใช้ JIS X 0201(https://en.m.wikipedia.org.org/wiki/JIS_X_0201) ซึ่งเป็นพื้นฐานของ Shift-JIS
    • คล้ายกัน พรอมป์ DOS ภาษาญี่ปุ่นเคยเป็น C:¥ ไม่ใช่ C:\
  • ส่วนขยายเหล่านี้คือ ฟีเจอร์ของ Ada ใน Ada มีเลเบลรูปแบบ Call (Param_A => 1, Param_B => "Foo");, ขีดล่างในตัวเลขฐานใดก็ได้ (X : Integer := 1_000;), ซับโปรแกรมซ้อนกัน และการตรวจสอบตามช่วงค่า
    • อย่างที่บทความบอก Pascal มีฟีเจอร์เหล่านี้มาก่อน Ada แล้ว และ task type ที่มี entry point ก็มองได้ว่าโดยพื้นฐานแล้วเป็น generator
      ดูเหมือนเรามักลืมกันว่า C ในยุคนั้นเป็นภาษาที่ดิบอย่างไม่น่าเชื่อเมื่อเทียบกับภาษาอื่น ๆ หลายภาษา
  • นอกเหนือจากเนื้อหาแล้ว typography ของหนังสือเล่มนี้ก็น่าสนใจ ให้ความรู้สึกทั้งสวยงามและน่ากลัวไปพร้อมกัน
    ผมไม่รู้กฎการเขียนภาษาญี่ปุ่นหรือกฎ kerning มากพอ แต่ดูเหมือนเอาฟอนต์แบบความกว้างแปรผันที่มีทั้งคันจิและอักษรละตินมายัดให้พอดีกับช่องแบบความกว้างคงที่
    อย่างไรก็ดี ดีตรงที่ตัวอย่างโค้ดไม่ได้ใช้ฟอนต์ 8pt เหมือนหนังสือหลายเล่มที่ผมมี
    • ในการจัดพิมพ์ภาษาญี่ปุ่นที่มีอักษรละตินปนอยู่ วิธีนี้ค่อนข้างพบได้บ่อย โดยเฉพาะในฟอนต์เก่า ๆ คำอธิบายที่นี่ค่อนข้างดี: https://www.reddit.com/r/typography/comments/vvfmpu/comment/...
  • พอเห็น generator แล้วทำให้นึกถึงปัญหา internal/external iteration ของ Rust และ try_fold() (https://scribe.rip/@veedrac/rust-is-slow-and-i-am-the-cure-3...)
  • โดยเฉพาะเมื่อดู generator แล้วดูเหมือนว่ามันล้ำยุคไปมาก อาจเป็นเพราะ Fujitsu ไม่ต้องใส่ใจกับ กระบวนการมาตรฐาน อันยาวนาน จึงสามารถลงมือ implement ได้เลย
    แต่ก็คงเพราะเหตุผลนั้นเอง ส่วนขยายเหล่านี้จึงไม่ค่อยเป็นที่รู้จัก และต้องถูกค้นพบใหม่และประดิษฐ์ซ้ำใน C/C++ สมัยใหม่ในอีกหลายทศวรรษต่อมา
    • ไม่ใช่ Fujitsu แต่เป็น MetaWare ต่างหาก MetaWare เป็นบริษัทที่มีประสบการณ์ด้านคอมไพเลอร์พอสมควร และในช่วงเวลาเดียวกันก็มีคอมไพเลอร์ Pascal ที่ค่อนข้างเป็นที่รู้จักด้วย ใน Pascal มี nested functions อยู่แล้ว
    • C อาจกลายเป็นภาษาที่ดีกว่านี้มาก ถ้าไม่ได้ถูกครอบงำโดยคนที่ยืนกรานว่าแม้แต่ 2's complement ก็ไม่ควรถูกใส่ไว้ในมาตรฐาน
    • coroutine และ generator เป็นแนวคิดที่เข้าใจกันดีอยู่แล้วในตอนนั้น ดู Icon ก็ได้ ดังนั้นเหตุผลหลักจริง ๆ ดูจะใกล้เคียงกับการที่ไม่ต้องกังวลเรื่อง ภาระของการมาตรฐาน มากกว่า