คำเตือนของการใช้ประเภทพื้นฐาน (เช่น int) เป็นชั้นเรียนคืออะไร?


27

เมื่อมีการออกแบบและ implenting ภาษาโปรแกรมเชิงวัตถุในบางจุดหนึ่งต้องให้ทางเลือกเกี่ยวกับการใช้ประเภทพื้นฐาน (เช่นint, float, doubleหรือเทียบเท่า) เป็นชั้นเรียนหรือสิ่งอื่นใด เห็นได้ชัดว่าภาษาในตระกูล C มีแนวโน้มที่จะไม่กำหนดเป็นคลาส (Java มีชนิดดั้งเดิมแบบพิเศษ C # ใช้ภาษาเหล่านี้เป็น struct ที่ไม่เปลี่ยนรูป ฯลฯ )

ฉันสามารถนึกถึงข้อได้เปรียบที่สำคัญมากเมื่อมีการใช้ประเภทพื้นฐานเป็นคลาส (ในระบบชนิดที่มีลำดับชั้นแบบรวม): ชนิดเหล่านี้อาจเป็นชนิดย่อย Liskov ที่เหมาะสมของประเภทรูต ดังนั้นเราจึงหลีกเลี่ยงความสับสนของภาษาด้วย Boxing / unboxing (ชัดเจนหรือโดยปริยาย) ประเภทของ wrapper กฎความแปรปรวนพิเศษพฤติกรรมพิเศษ ฯลฯ

แน่นอนฉันสามารถเข้าใจบางส่วนว่าทำไมนักออกแบบภาษาจึงตัดสินใจเลือกวิธีการ: อินสแตนซ์ของชั้นเรียนมักจะมีค่าใช้จ่ายเชิงพื้นที่ (เนื่องจากอินสแตนซ์อาจมี vtable หรือข้อมูลเมตาอื่น ๆ ในโครงร่างหน่วยความจำ) มี (ถ้าภาษาไม่อนุญาตให้สืบทอดกับสิ่งเหล่านั้น)

ประสิทธิภาพเชิงพื้นที่ (และพื้นที่เชิงพื้นที่ที่ได้รับการปรับปรุงโดยเฉพาะในอาร์เรย์ขนาดใหญ่) เป็นเหตุผลเดียวที่ว่าทำไมประเภทพื้นฐานมักไม่ได้เรียน?

โดยทั่วไปฉันคิดว่าคำตอบคือใช่ แต่คอมไพเลอร์มีอัลกอริธึมการวิเคราะห์แบบ Escape และพวกเขาสามารถอนุมานได้ว่าพวกเขาสามารถ (เลือก) ละเว้นค่าใช้จ่ายเชิงพื้นที่เมื่ออินสแตนซ์ (ตัวอย่างใด ๆ ไม่ใช่แค่ชนิดพื้นฐาน) ได้รับการพิสูจน์อย่างเคร่งครัด ในประเทศ

เป็นความผิดพลาดข้างต้นหรือมีสิ่งอื่นที่ฉันขาดหายไปหรือไม่


คำตอบ:


19

ใช่มันค่อนข้างมีประสิทธิภาพ แต่ดูเหมือนว่าคุณจะประเมินผลกระทบต่ำกว่าความเป็นจริง

ก่อนอื่นมันไม่ใช่แค่ "ค่าใช้จ่ายเชิงพื้นที่" การทำกล่องบรรจุแบบดั้งเดิม / การจัดสรรฮีปมีค่าใช้จ่ายด้วยเช่นกัน มีความกดดันเพิ่มเติมเกี่ยวกับ GC ในการจัดสรรและรวบรวมวัตถุเหล่านั้น สิ่งนี้จะทวีคูณถ้า "วัตถุดั้งเดิม" ไม่เปลี่ยนรูปตามที่ควรจะเป็น จากนั้นมีแคชที่หายไปมากขึ้น (ทั้งคู่เกิดจากความผิดพลาดและเนื่องจากข้อมูลน้อยกว่าที่ควรเป็นจำนวนแคชที่กำหนด) บวกกับความจริงที่ว่า "โหลดที่อยู่ของวัตถุแล้วโหลดค่าจริงจากที่อยู่" ต้องใช้คำแนะนำมากกว่า "โหลดค่าโดยตรง"

ประการที่สองการวิเคราะห์การหลบหนีไม่ได้เป็นฝุ่นธุลีมากขึ้น มันใช้กับค่าที่ดีอย่าหนีไป แน่นอนว่ามันเป็นสิ่งที่ดีในการเพิ่มประสิทธิภาพการคำนวณในท้องถิ่น (เช่นตัวนับลูปและผลการคำนวณระดับกลาง) และจะให้ประโยชน์ที่วัดได้ แต่ค่าส่วนใหญ่มีขนาดใหญ่กว่าอาศัยอยู่ในเขตข้อมูลของวัตถุและอาร์เรย์ จริงอยู่สิ่งเหล่านี้อาจมีการวิเคราะห์การหลบหนีด้วยตัวเอง แต่โดยปกติแล้วพวกมันมักจะเป็นประเภทอ้างอิงที่ไม่แน่นอนดังนั้นการใช้นามแฝงของพวกเขาจึงเป็นเรื่องท้าทายที่สำคัญสำหรับการวิเคราะห์การหลบหนีซึ่งตอนนี้ต้องพิสูจน์ว่า และ (2) ไม่ได้สร้างความแตกต่างสำหรับวัตถุประสงค์ในการกำจัดการจัดสรร

ระบุว่าการเรียกวิธีการใด ๆ (รวมทั้ง getters) หรือผ่านวัตถุเป็นอาร์กิวเมนต์ใดวิธีการอื่น ๆ สามารถช่วยหลบหนีวัตถุที่คุณจะต้องวิเคราะห์ interprocedural ในทุกกรณี แต่ที่น่ารำคาญที่สุด นี่แพงและซับซ้อนกว่ามาก

แล้วก็มีหลายกรณีที่สิ่งต่าง ๆ หลุดรอดไปและไม่สามารถปรับให้เหมาะสมได้ จริง ๆ แล้วถ้าคุณพิจารณาว่าโปรแกรมเมอร์ซีบ่อยแค่ไหนที่ประสบปัญหาการจัดสรรฮีป เมื่อวัตถุที่มี int escapes การวิเคราะห์ escape นั้นสิ้นสุดลงเพื่อใช้กับ int เช่นกัน บอกลาดั้งเดิมที่มีประสิทธิภาพสาขา

สิ่งนี้เชื่อมโยงกับอีกจุดหนึ่ง: การวิเคราะห์และการปรับให้เหมาะสมที่จำเป็นนั้นมีความซับซ้อนอย่างจริงจังและเป็นพื้นที่ของการวิจัย เป็นที่ถกเถียงกันว่าการใช้ภาษาใด ๆ ประสบความสำเร็จในระดับสูงสุดที่คุณแนะนำหรือไม่และถึงแม้ว่าจะเป็นเช่นนั้น การยืนบนไหล่ของยักษ์ใหญ่เหล่านี้นั้นง่ายกว่าการเป็นยักษ์ แต่ก็ยังห่างไกลจากเรื่องเล็กน้อย อย่าคาดหวังว่าผลการแข่งขันจะเกิดขึ้นในช่วงสองสามปีแรก

ไม่ได้หมายความว่าภาษาเหล่านั้นจะไม่สามารถใช้งานได้ เห็นได้ชัดว่าพวกเขาเป็น อย่าเพิ่งคิดว่ามันจะเป็นแบบบรรทัดต่อบรรทัดเร็วเท่ากับภาษาที่มีภาษาดั้งเดิมโดยเฉพาะ ในคำอื่น ๆ ไม่หลอกตัวเองด้วยวิสัยทัศน์ของคอมไพเลอร์สมาร์ทพอ


เมื่อพูดถึงการวิเคราะห์การหลบหนีฉันก็หมายถึงการจัดสรรให้กับที่เก็บข้อมูลอัตโนมัติ (มันไม่ได้แก้ปัญหาทุกอย่าง แต่อย่างที่คุณบอกว่ามันแก้ปัญหาบางอย่างได้) ฉันยังยอมรับว่าฉันประเมินค่าต่ำสุดว่าฟิลด์และนามแฝงใดสามารถทำให้การวิเคราะห์การหลบหนีล้มเหลวได้บ่อยขึ้น แคชคิดถึงเป็นสิ่งที่ฉันกังวลมากที่สุดเมื่อพูดถึงประสิทธิภาพเชิงพื้นที่ดังนั้นขอบคุณที่พูดถึงเรื่องนั้น
Theodoros Chatzigiannakis

@TheodorosChatzigiannakis ฉันรวมถึงการเปลี่ยนกลยุทธ์การจัดสรรในการวิเคราะห์การหลบหนี (เพราะจริงๆแล้วดูเหมือนจะเป็นสิ่งเดียวที่เคยใช้)

อ้างอิงย่อหน้าที่สองของคุณ: วัตถุไม่จำเป็นต้องจัดสรรฮีปหรือเป็นประเภทอ้างอิงเสมอไป ในความเป็นจริงเมื่อไม่ได้สิ่งนี้ทำให้การเพิ่มประสิทธิภาพที่จำเป็นเปรียบเทียบง่าย ดูตัวอย่างออบเจกต์ที่ปันส่วนของ C ++ สำหรับตัวอย่างแรก ๆ และระบบความเป็นเจ้าของของ Rust เพื่อหาวิธีวิเคราะห์การหลบหนีเข้าสู่ภาษาโดยตรง
amon

@ ฉันรู้และบางทีฉันควรทำให้ชัดเจนกว่านี้ แต่ดูเหมือนว่า OP จะสนใจเฉพาะภาษาจาวาและภาษา C # ซึ่งการจัดสรรฮีปนั้นเป็นข้อบังคับเกือบจะบังคับ (และโดยปริยาย) เนื่องจากความหมายอ้างอิง จุดที่ดีเกี่ยวกับสนิมโดยใช้สิ่งที่มีจำนวนมากเพื่อหลบหนีการวิเคราะห์!

@delnan มันเป็นความจริงฉันส่วนใหญ่สนใจในภาษาที่เป็นนามธรรมเก็บรายละเอียดการจัดเก็บข้อมูล แต่โปรดอย่าลังเลที่จะรวมสิ่งที่คุณคิดว่ามีความเกี่ยวข้องแม้ว่าจะไม่สามารถใช้ได้กับภาษาเหล่านั้น
Theodoros Chatzigiannakis

27

ประสิทธิภาพเชิงพื้นที่ (และพื้นที่เชิงพื้นที่ที่ได้รับการปรับปรุงโดยเฉพาะในอาร์เรย์ขนาดใหญ่) เป็นเหตุผลเดียวที่ว่าทำไมประเภทพื้นฐานมักไม่ได้เรียน?

เลขที่

อีกประเด็นคือประเภทพื้นฐานมีแนวโน้มที่จะถูกใช้โดยการดำเนินงานพื้นฐาน คอมไพเลอร์จำเป็นต้องรู้ว่าint + intจะไม่ถูกคอมไพล์ไปยังการเรียกใช้ฟังก์ชั่น แต่เป็นการสอนขั้นพื้นฐานของ CPU (หรือรหัสไบต์เทียบเท่า) ณ จุดนี้หากคุณมีintวัตถุปกติคุณจะต้องยกเลิกการทำสิ่งต่าง ๆ อย่างมีประสิทธิภาพ

การเรียงลำดับเหล่านั้นยังไม่ค่อยสนุกกับการพิมพ์ย่อย คุณไม่สามารถส่งไปยังคำสั่ง CPU ได้ คุณไม่สามารถส่งจากคำสั่ง CPU ได้ ผมหมายถึงจุดทั้งหมดของ subtyping เพื่อให้คุณสามารถใช้สถานที่ที่คุณสามารถD Bคำแนะนำเกี่ยวกับ CPU ไม่ใช่ polymorphic ในการรับข้อมูลพื้นฐานให้ทำเช่นนั้นคุณต้องปิดการดำเนินงานด้วยตรรกะการจัดส่งที่มีค่าใช้จ่ายหลายเท่าของจำนวนการดำเนินการเป็นการเพิ่มแบบง่าย ๆ (หรืออะไรก็ตาม) ประโยชน์ของการintเป็นส่วนหนึ่งของลำดับชั้นของประเภทจะกลายเป็นสิ่งที่สงสัยเล็กน้อยเมื่อมันถูกผนึก / ขั้นสุดท้าย และนั่นคือการไม่สนใจอาการปวดหัวทั้งหมดด้วยตรรกะการจัดส่งสำหรับผู้ประกอบการไบนารี ...

โดยพื้นฐานแล้วประเภทดั้งเดิมจะต้องมีกฎพิเศษมากมายเกี่ยวกับวิธีที่คอมไพเลอร์จัดการกับพวกเขาและสิ่งที่ผู้ใช้สามารถทำกับประเภทของพวกเขาต่อไปดังนั้นจึงมักจะง่ายกว่าที่จะปฏิบัติกับพวกเขาอย่างชัดเจน


4
ตรวจสอบการใช้ภาษาที่พิมพ์แบบไดนามิกใด ๆ ที่จัดการกับจำนวนเต็มและเช่นวัตถุ คำสั่งซีพียูดั้งเดิมขั้นสุดท้ายสามารถซ่อนอยู่ในเมธอด (ตัวดำเนินการโอเวอร์โหลด) เป็นอย่างดีในการประยุกต์ใช้คลาสที่ค่อนข้างมีสิทธิพิเศษในไลบรารีรันไทม์ รายละเอียดจะดูแตกต่างกับระบบชนิดคงที่และคอมไพเลอร์ แต่ไม่มีปัญหาพื้นฐาน ที่แย่ที่สุดมันทำให้สิ่งต่าง ๆ ช้าลง

3
int + intสามารถเป็นโอเปอเรเตอร์ระดับภาษาปกติที่เรียกใช้คำสั่งภายในที่รับประกันว่าจะคอมไพล์เพื่อ (หรือประพฤติตนเป็น) การเพิ่มจำนวนเต็มของ CPU ดั้งเดิม ประโยชน์ของintการสืบทอดจากobjectไม่ได้เป็นเพียงความเป็นไปได้ของการสืบทอดประเภทจากผู้อื่นintแต่ยังเป็นไปได้ของนั้นintมีพฤติกรรมเป็นobjectโดยไม่ต้องมวย พิจารณา C # generics: คุณสามารถมีความแปรปรวนร่วมและความแปรปรวนได้ แต่มันจะใช้ได้กับประเภทคลาสเท่านั้น - ประเภทของ struct จะถูกแยกออกโดยอัตโนมัติเพราะมันสามารถกลายเป็นobjectมวยที่ผ่าน (โดยปริยาย, คอมไพเลอร์)
Theodoros Chatzigiannakis

3
@delnan - แน่นอนแม้ว่าในประสบการณ์ของฉันกับการใช้งานแบบคงที่เนื่องจากทุกการโทรที่ไม่ใช่ระบบทำให้การดำเนินงานดั้งเดิมมีค่าใช้จ่ายที่มีผลกระทบอย่างมากต่อประสิทธิภาพ - ซึ่งจะมีผลกระทบอย่างมากยิ่งขึ้นกับการยอมรับ
Telastyn

@TheodorosChatzigiannakis - ยอดเยี่ยมดังนั้นคุณสามารถรับความแปรปรวนและความแปรปรวนของประเภทที่ไม่มีประโยชน์ sub / super-type ... และการใช้ตัวดำเนินการพิเศษเพื่อเรียกคำสั่ง CPU ยังคงพิเศษ ฉันไม่เห็นด้วยกับความคิด - ฉันทำสิ่งที่คล้ายกันมากในภาษาของเล่นของฉัน แต่ฉันพบว่ามี gotchas ที่ใช้งานได้จริงในระหว่างการนำไปใช้งานซึ่งไม่ได้ทำให้สิ่งต่าง ๆ สะอาดเท่าที่คุณคาดหวัง
Telastyn

1
@TheodorosChatzigiannakis การฝังข้ามขอบเขตห้องสมุดเป็นไปได้อย่างแน่นอนแม้ว่าจะเป็นรายการอื่นใน "การเพิ่มประสิทธิภาพระดับสูงที่ฉันต้องการมี" รายการช้อปปิ้ง ฉันรู้สึกว่าจำเป็นต้องชี้ให้เห็นว่ามันเป็นเรื่องยากที่จะได้รับสิทธิอย่างสมบูรณ์โดยไม่ต้องถูกอนุรักษ์จนไร้ประโยชน์

4

มีเพียงไม่กี่กรณีที่คุณต้องการ "ชนิดพื้นฐาน" เป็นวัตถุเต็มรูปแบบ (ที่นี่วัตถุคือข้อมูลที่มีตัวชี้ไปยังกลไกการจัดส่งหรือถูกแท็กด้วยประเภทที่สามารถใช้โดยกลไกการจัดส่ง):

  • คุณต้องการให้ผู้ใช้กำหนดประเภทเพื่อให้สามารถสืบทอดจากประเภทพื้นฐาน สิ่งนี้มักจะไม่ต้องการเพราะมันแนะนำให้ปวดหัวเกี่ยวกับประสิทธิภาพและความปลอดภัย มันเป็นปัญหาด้านประสิทธิภาพเนื่องจากการคอมไพล์ไม่สามารถสันนิษฐานได้ว่าintพินัยกรรมจะมีขนาดคงที่เฉพาะเจาะจงหรือไม่มีวิธีใดที่ถูกแทนที่และมันเป็นปัญหาด้านความปลอดภัยเพราะซีแมนทิกส์ของints อาจถูกล้มล้าง (พิจารณาจำนวนเต็มที่เท่ากับจำนวนใด ๆ หรือ ที่เปลี่ยนค่าของมันมากกว่าจะไม่เปลี่ยนรูป)

  • ประเภทดั้งเดิมของคุณมี supertype และคุณต้องการให้มีตัวแปรที่มีประเภท supertype ของประเภทดั้งเดิม ตัวอย่างเช่นสมมติว่าคุณintเป็นHashableและคุณต้องการประกาศฟังก์ชั่นที่ใช้Hashableพารามิเตอร์ที่อาจได้รับวัตถุปกติ แต่ยังints

    สิ่งนี้สามารถ“ แก้ไข” โดยการทำให้ประเภทผิดกฎหมาย: กำจัดการพิมพ์ย่อยและตัดสินใจว่าอินเตอร์เฟสไม่ใช่ประเภท แต่เป็นข้อ จำกัด ประเภท เห็นได้ชัดว่าช่วยลดการแสดงออกของระบบประเภทของคุณและระบบประเภทดังกล่าวจะไม่ถูกเรียกว่าเชิงวัตถุอีกต่อไป ดู Haskell สำหรับภาษาที่ใช้กลยุทธ์นี้ C ++ อยู่ครึ่งทางเพราะประเภทดั้งเดิมไม่มีซุปเปอร์ไทป์

    ทางเลือกเต็มหรือบางส่วนของมวยประเภทพื้นฐาน ประเภทการชกมวยไม่จำเป็นต้องปรากฏให้ผู้ใช้เห็น เป็นหลักคุณกำหนดประเภทกล่องภายในสำหรับแต่ละประเภทพื้นฐานและการแปลงโดยนัยระหว่างกล่องชนิดและชนิดพื้นฐาน สิ่งนี้สามารถทำให้งุ่มง่ามหากประเภทที่บรรจุอยู่มีความหมายต่างกัน Java แสดงปัญหาสองประการ: ชนิดบรรจุกล่องมีแนวคิดของตัวตนในขณะที่ดั้งเดิมมีเพียงแนวคิดของการเทียบเท่าค่าและประเภทชนิดบรรจุกล่องเป็นโมฆะในขณะที่ดั้งเดิมจะถูกต้องเสมอ ปัญหาเหล่านี้สามารถหลีกเลี่ยงได้อย่างสมบูรณ์โดยไม่เสนอแนวคิดเกี่ยวกับตัวตนสำหรับประเภทของมูลค่าเสนอตัวดำเนินการมากเกินไปและไม่ทำให้วัตถุทั้งหมดเป็นโมฆะโดยค่าเริ่มต้น

  • คุณไม่มีฟีเจอร์การพิมพ์สแตติก ตัวแปรอาจเก็บค่าใด ๆ รวมถึงชนิดดั้งเดิมหรือวัตถุ ดังนั้นประเภทดั้งเดิมทั้งหมดจะต้องมีกล่องเสมอเพื่อรับประกันการพิมพ์ที่แข็งแกร่ง

ภาษาที่มีการพิมพ์แบบสแตติกทำได้ดีในการใช้ประเภทดั้งเดิมเมื่อใดก็ตามที่เป็นไปได้และถอยกลับไปเป็นชนิดกล่องเป็นทางเลือกสุดท้าย ในขณะที่หลาย ๆ โปรแกรมไม่ไวต่อประสิทธิภาพอย่างมาก แต่ก็มีบางกรณีที่ขนาดและการแต่งหน้าของรูปแบบดั้งเดิมนั้นมีความเกี่ยวข้องอย่างยิ่ง: ลองคิดตัวเลขจำนวนมากที่คุณต้องการใส่จุดข้อมูลจำนวนพันล้านจุดในหน่วยความจำ เปลี่ยนจากdoubleเป็นfloatอาจเป็นกลยุทธ์การปรับพื้นที่ว่างให้ทำงานได้ใน C แต่จะไม่มีผลใด ๆ หากประเภทตัวเลขทั้งหมดถูกบรรจุอยู่ในกล่องเสมอ (และทำให้เสียหน่วยความจำอย่างน้อยครึ่งหนึ่งสำหรับตัวชี้กลไกการจัดส่ง) เมื่อมีการใช้งานประเภทดั้งเดิมในกล่องมันค่อนข้างตรงไปตรงมาที่จะลบมวยผ่านการใช้คอมไพเลอร์อินทริน แต่มันจะมองสั้นเพื่อเดิมพันประสิทธิภาพโดยรวมของภาษาของคุณใน "คอมไพเลอร์ขั้นสูงพอเพียง"


An intแทบจะไม่เปลี่ยนรูปเลยในทุกภาษา
Scott Whitlock

6
@ScottWhitlock ฉันเห็นว่าทำไมคุณถึงคิดว่า แต่ในประเภทดึกดำบรรพ์ทั่วไปเป็นประเภทค่าที่ไม่เปลี่ยนรูปแบบ ไม่มีภาษาที่มีสติช่วยให้คุณเปลี่ยนค่าของหมายเลขเจ็ด อย่างไรก็ตามหลายภาษาอนุญาตให้คุณกำหนดตัวแปรที่เก็บค่าชนิดดั้งเดิมเป็นค่าอื่น ในภาษา C-like ตัวแปรคือตำแหน่งหน่วยความจำที่กำหนดชื่อ ตัวแปรไม่เหมือนกับค่าที่ชี้ไป intค่าจะไม่เปลี่ยนรูป แต่intตัวแปรไม่ได้
amon

1
@amon: ไม่มีภาษาที่มีไหวพริบ; เพียง Java: thedailywtf.com/articles/Disgruntled-Bomb-Java-Edition
Mason Wheeler

get rid of subtyping and decide that interfaces aren't types but type constraints.... such a type system wouldn't be called object-oriented any longer แต่ฟังดูเหมือนโปรแกรมต้นแบบที่ใช้ OOP แน่นอน
Michael

1
@ScottWhitlock คำถามคือถ้าคุณมี int b = a คุณสามารถทำบางสิ่งบางอย่างเพื่อ b ที่จะเปลี่ยนค่าของ a มีการใช้งานภาษาบางอย่างที่เป็นไปได้ แต่โดยทั่วไปถือว่าเป็นพยาธิวิทยาและไม่พึงประสงค์ซึ่งแตกต่างจากการทำแบบเดียวกันสำหรับอาร์เรย์
Random832

2

การใช้งานส่วนใหญ่ฉันตระหนักถึงการกำหนดข้อ จำกัด สามประการสำหรับคลาสที่อนุญาตให้คอมไพเลอร์ใช้ชนิดดั้งเดิมได้อย่างมีประสิทธิภาพเนื่องจากการเป็นตัวแทนพื้นฐานส่วนใหญ่ของเวลา ข้อ จำกัด เหล่านี้คือ:

  • การเปลี่ยนไม่ได้
  • วาระสุดท้าย (ไม่สามารถหาได้จาก)
  • การพิมพ์แบบคงที่

สถานการณ์ที่คอมไพเลอร์จำเป็นต้องใส่กล่องดั้งเดิมเข้าไปในวัตถุในการแทนพื้นฐานนั้นค่อนข้างหายากเช่นเมื่อการObjectอ้างอิงชี้ไปที่มัน

นี่เป็นการเพิ่มการจัดการกรณีพิเศษในคอมไพเลอร์ แต่มันไม่ได้ จำกัด เพียงแค่คอมไพเลอร์ขั้นสูงระดับสูงในตำนานบางตัวเท่านั้น การเพิ่มประสิทธิภาพนั้นอยู่ในคอมไพเลอร์ผลิตจริงในภาษาหลัก สกาล่ายังช่วยให้คุณสามารถกำหนดคลาสค่าของคุณเอง


1

ใน Smalltalk พวกมันทั้งหมด (int, float, ฯลฯ ) เป็นวัตถุชั้นหนึ่ง เพียงกรณีพิเศษคือ SmallIntegers กำลังประมวลผลและรับการรักษาที่แตกต่างจากเครื่องเสมือนจริงเพื่อประโยชน์ของประสิทธิภาพและดังนั้นจึงชั้น SmallInteger จะไม่ยอมรับ subclasses (ซึ่งไม่ได้เป็นข้อ จำกัด ในทางปฏิบัติ.) หมายเหตุว่านี้ไม่จำเป็นต้องมีการพิจารณาเป็นพิเศษใด ๆ ในส่วนของโปรแกรมเมอร์ในขณะที่ความแตกต่างจะถูก จำกัด ขอบเขตให้กับรูทีนอัตโนมัติเช่นการสร้างรหัสหรือการรวบรวมขยะ

ทั้งคอมไพเลอร์ Smalltalk (ซอร์สโค้ด -> VM bytecodes) และ VM nativizer (bytecodes -> รหัสเครื่อง) ปรับแต่งโค้ดที่สร้างขึ้น (JIT) เพื่อลดการลงโทษของการดำเนินการเบื้องต้นด้วยวัตถุพื้นฐานเหล่านี้


1

ฉันได้รับการออกแบบให้ใช้ OO อย่างรวดเร็วและรันไทม์ (นี่เป็นเหตุผลที่แตกต่างไปจากเดิมอย่างสิ้นเชิง)

ไม่มีอะไรผิดปกติกับการทำสิ่งต่าง ๆ เช่นชั้นเรียนที่แท้จริง int; ในความเป็นจริงสิ่งนี้ทำให้ GC ง่ายต่อการออกแบบเนื่องจากขณะนี้มีส่วนหัวฮีปเพียง 2 ชนิด (คลาส & อาร์เรย์) มากกว่า 3 (คลาสอาร์เรย์และดั้งเดิม) [ความจริงที่ว่าเราสามารถรวมคลาสและอาร์เรย์หลังจากนี้ไม่เกี่ยวข้องกัน ]

กรณีที่สำคัญจริงประเภทดั้งเดิมควรมีวิธีสุดท้าย / ปิดผนึกส่วนใหญ่ (+ เรื่องสำคัญ ToString ไม่มาก) สิ่งนี้ทำให้คอมไพเลอร์แก้ไขการโทรไปยังฟังก์ชั่นได้เกือบทั้งหมดและอินไลน์ด้วยตนเอง ในกรณีส่วนใหญ่สิ่งนี้ไม่สำคัญว่าจะเป็นพฤติกรรมการคัดลอก (ฉันเลือกที่จะทำให้สามารถใช้งานได้ในระดับภาษา [เช่น. NET]) แต่ในบางกรณีหากวิธีการที่ไม่ได้ปิดผนึกคอมไพเลอร์จะถูกบังคับให้สร้างการโทร ฟังก์ชั่นที่ใช้ในการสร้าง int + int

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.