เหตุใดการอนุมานประเภทจึงมีประโยชน์


37

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

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

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


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

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

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

2
อธิบายอย่างถี่ถ้วนในประเด็นแรกของ @JimmyHoffa ลองอ่านโดยทั่วไป ประโยคที่ง่ายกว่าในการแยกวิเคราะห์และอ่านให้เข้าใจเพียงอย่างเดียวเมื่อมุ่งเน้นไปที่ส่วนของคำพูดของแต่ละคำ? "วัว (บทความ) วัว (คำนามเอกพจน์) กระโดด (คำกริยาในอดีต) มากกว่า (คำบุพบท) (บทความ) ดวงจันทร์ (คำนาม). (เครื่องหมายวรรคตอนระยะเวลา)"
Zev Spitz

คำตอบ:


46

ลองดูที่ Java Java ไม่สามารถมีตัวแปรที่มีประเภทที่อนุมานได้ นี่หมายความว่าฉันต้องสะกดคำแบบนี้บ่อยครั้งแม้ว่ามันจะเป็นที่ชัดเจนสำหรับผู้อ่านที่เป็นมนุษย์ประเภท:

int x = 42;  // yes I see it's an int, because it's a bloody integer literal!

// Why the hell do I have to spell the name twice?
SomeObjectFactory<OtherObject> obj = new SomeObjectFactory<>();

และบางครั้งมันก็แค่น่ารำคาญที่จะสะกดออกทั้งประเภท

// this code walks through all entries in an "(int, int) -> SomeObject" table
// represented as two nested maps
// Why are there more types than actual code?
for (Map.Entry<Integer, Map<Integer, SomeObject<SomeObject, T>>> row : table.entrySet()) {
    Integer rowKey = entry.getKey();
    Map<Integer, SomeObject<SomeObject, T>> rowValue = entry.getValue();
    for (Map.Entry<Integer, SomeObject<SomeObject, T>> col : rowValue.entrySet()) {
        Integer colKey = col.getKey();
        SomeObject<SomeObject, T> colValue = col.getValue();
        doSomethingWith<SomeObject<SomeObject, T>>(rowKey, colKey, colValue);
    }
}

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

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

มีหลายภาษาที่รองรับการอนุมานประเภท ตัวอย่างเช่น:

  • C ++ autoประเภททริกเกอร์คำหลักอนุมาน ก็ไม่มีการสะกดคำว่าประเภท lambdas หรือรายการในภาชนะบรรจุจะเป็นนรก

  • C # คุณสามารถประกาศตัวแปรด้วยvarซึ่งก่อให้เกิดการอนุมานแบบ จำกัด รูปแบบ มันยังคงจัดการกรณีส่วนใหญ่ที่คุณต้องการอนุมานประเภท ในบางสถานที่คุณสามารถออกจากประเภทได้อย่างสมบูรณ์ (เช่นใน lambdas)

  • Haskell และภาษาใด ๆ ในตระกูล ML ในขณะที่รสชาติเฉพาะของการอนุมานประเภทที่ใช้ในที่นี้ค่อนข้างทรงพลัง แต่คุณยังคงเห็นหมายเหตุประกอบประเภทสำหรับฟังก์ชั่นและด้วยเหตุผลสองประการ: ข้อแรกคือเอกสารประกอบและประการที่สองคือการตรวจสอบว่าการอนุมานชนิดนั้น หากมีความคลาดเคลื่อนอาจมีข้อผิดพลาดบางประเภท


13
โปรดทราบว่า C # มีประเภทที่ไม่ระบุตัวตนเช่นประเภทที่ไม่มีชื่อ แต่ C # มีระบบประเภทที่ระบุเช่นระบบประเภทตามชื่อ หากไม่มีการอนุมานประเภทจะไม่สามารถใช้ประเภทเหล่านั้นได้!
Jörg W Mittag

10
ตัวอย่างบางอย่างที่ฉันคิดไว้ การเริ่มต้น 42 ไม่ได้โดยอัตโนมัติหมายความว่าตัวแปรเป็นintมันอาจจะเป็นประเภทที่เป็นตัวเลขใด ๆ charรวมถึง นอกจากนี้ฉันไม่เห็นสาเหตุที่คุณต้องการสะกดทั้งประเภทEntryเมื่อคุณสามารถพิมพ์ชื่อคลาสและให้ IDE ของคุณนำเข้าที่จำเป็น กรณีเดียวเมื่อคุณต้องสะกดชื่อทั้งหมดคือเมื่อคุณมีชั้นเรียนที่มีชื่อเดียวกันในแพ็คเกจของคุณเอง แต่ดูเหมือนว่าฉันจะชอบการออกแบบที่ไม่ดีอยู่ดี
Malcolm

10
@ Malcolm ใช่ตัวอย่างทั้งหมดของฉันมีการวางแผน พวกเขาทำหน้าที่อธิบายจุด เมื่อฉันเขียนintตัวอย่างฉันกำลังคิดเกี่ยวกับ (ในความคิดของฉันพฤติกรรมที่มีสติสัมปชัญญะ) ของภาษาส่วนใหญ่ที่อนุมานประเภทคุณลักษณะ พวกเขามักจะอนุมานintหรือIntegerหรือสิ่งที่เรียกว่าในภาษานั้น ความสวยงามของการอนุมานประเภทคือมันเป็นตัวเลือกเสมอ คุณยังสามารถระบุประเภทที่แตกต่างได้หากคุณต้องการ เกี่ยวกับตัวอย่างเช่นจุดที่ดีฉันจะแทนที่ด้วยEntry Map.Entry<Integer, Map<Integer, SomeObject<SomeObject, T>>>Java ไม่ได้มีประเภทนามแฝง :(
อมร

4
@ m3th0dman ถ้าประเภทมีความสำคัญต่อความเข้าใจคุณสามารถพูดถึงมันได้อย่างชัดเจน การอนุมานประเภทเป็นตัวเลือกเสมอ แต่ที่นี่ประเภทของการcolKeyเป็นทั้งที่เห็นได้ชัดและไม่เกี่ยวข้อง: doSomethingWithเราจะดูแลเกี่ยวกับมันเป็นที่เหมาะสมเป็นอาร์กิวเมนต์ที่สองของ ถ้าฉันจะดึงห่วงที่เป็นฟังก์ชั่นที่อัตราผลตอบแทนถัว Iterable ของ(key1, key2, value)-triples <K1, K2, V> Iterable<TableEntry<K1, K2, V>> flattenTable(Map<K1, Map<K2, V>> table)ลายเซ็นทั่วไปส่วนใหญ่จะเป็น ภายในฟังก์ชั่นนั้นประเภทที่แท้จริงของcolKey( Integerไม่ใช่K2) ไม่เกี่ยวข้องอย่างแน่นอน
amon

4
@ m3th0dman มันเป็นคำสั่งกว้าง ๆ เกี่ยวกับโค้ด " ส่วนใหญ่ " ที่เป็นแบบนี้ สถิติเล็ก ๆ น้อย ๆ มีแน่นอนจุดในการเขียนประเภทสองครั้งใน initializers View.OnClickListener listener = new View.OnClickListener()ไม่มี: คุณจะยังคงรู้ประเภทแม้ว่าโปรแกรมเมอร์จะ "ขี้เกียจ" และย่อให้สั้นลงvar listener = new View.OnClickListener(หากเป็นไปได้) การเรียงลำดับของความซ้ำซ้อนนี้เป็นเรื่องธรรมดา - ฉันจะไม่เสี่ยง guesstimate ที่นี่ - และลบมันไม่เกิดจากความคิดเกี่ยวกับผู้อ่านในอนาคต คุณสมบัติทุกภาษาควรใช้ด้วยความระมัดระวังฉันไม่ได้ตั้งคำถามว่า
Konrad Morawski

26

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

และมันก็เป็นประสบการณ์ของฉันที่บ่อยครั้งประเภทที่แน่นอนไม่สำคัญ (นั้น) x + y * zแน่นอนคุณบางครั้งการแสดงออกรัง: monkey.eat(bananas.get(i)), factory.makeCar().drive(), แต่ละเหล่านี้มีการแสดงออกย่อยที่ประเมินเป็นค่าชนิดที่ไม่ได้เขียนออกมา แต่พวกเขามีความชัดเจนอย่างสมบูรณ์แบบ เราโอเคที่จะออกจากประเภทที่ไม่ได้ระบุไว้เพราะมันง่ายพอที่จะคิดออกจากบริบทและการเขียนออกมาจะเป็นอันตรายมากกว่าดี (ถ่วงความเข้าใจในการไหลของข้อมูลใช้หน้าจอที่มีค่าและพื้นที่หน่วยความจำระยะสั้น)

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

user = db.get_poster(request.post['answer'])
name = db.get_display_name(user)

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

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


2
+1 นี่คือคำตอบที่ได้รับการยอมรับ มันไปที่หัวใจของการอนุมานประเภทเป็นความคิดที่ดี
Christian Hayter

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

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

4

ฉันคิดว่าการอนุมานประเภทนั้นค่อนข้างสำคัญและควรได้รับการสนับสนุนในภาษาที่ทันสมัย เราทุกคนมีการพัฒนาใน IDEs viและพวกเขาจะช่วยได้มากในกรณีที่คุณต้องการที่จะทราบชนิดอนุมานเพียงไม่กี่ของเราสับใน ลองนึกถึงการใช้คำฟุ่มเฟื่อยและรหัสพิธีใน Java

  Map<String,HashMap<String,String>> map = getMap();

แต่คุณสามารถพูดได้ว่ามันดี IDE ของฉันจะช่วยฉันมันอาจเป็นจุดที่ถูกต้อง อย่างไรก็ตามคุณสมบัติบางอย่างจะไม่อยู่ที่นั่นหากไม่มีความช่วยเหลือในการอนุมานประเภท, C # ประเภทที่ไม่ระบุชื่อ

 var person = new {Name="John Smith", Age = 105};

Linq คงไม่ดีเท่าที่เป็นอยู่ตอนนี้โดยปราศจากการอนุมานจากประเภทSelectเช่น

  var result = list.Select(c=> new {Name = c.Name.ToUpper(), Age = c.DOB - CurrentDate});

ประเภทที่ไม่ระบุชื่อนี้จะอนุมานตัวแปรอย่างเรียบร้อย

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


Map<String,HashMap<String,String>>? แน่นอนว่าถ้าคุณไม่ได้ใช้ประเภทการสะกดคำเหล่านั้นมีประโยชน์น้อยมาก Table<User, File, String>ให้ข้อมูลมากกว่านี้และมีประโยชน์ในการเขียน
MikeFHay

4

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

ซึ่งยังบอกคุณเมื่อคุณควรหรือไม่ควรใช้ - เมื่อข้อมูลไม่ซ้ำซ้อน


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

@leftaroundabout: ซ้ำซ้อนเมื่อโปรแกรมเมอร์อ่าน
jmoreno

3

สมมติว่าหนึ่งเห็นรหัส:

someBigLongGenericType variableName = someBigLongGenericType.someFactoryMethod();

หากsomeBigLongGenericTypeกำหนดได้จากประเภทส่งคืนผู้ที่someFactoryMethodอ่านรหัสจะมีแนวโน้มว่าจะสังเกตเห็นว่าประเภทไม่ตรงกันหรือไม่และคนที่สังเกตเห็นความแตกต่างได้อย่างง่ายดายจะทราบได้อย่างไรว่ามันเป็นการจงใจหรือไม่

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


2

ฉันเห็นว่ามีคำตอบที่ดีจำนวนหนึ่งอยู่แล้ว บางอย่างที่ฉันจะทำซ้ำ แต่บางครั้งคุณเพียงต้องการที่จะใส่สิ่งต่าง ๆ ในคำพูดของคุณเอง ฉันจะแสดงความคิดเห็นด้วยตัวอย่างจาก C ++ เพราะนั่นคือภาษาที่ฉันคุ้นเคยมากที่สุด

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

struct {
    double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;

C ++ 11 เพิ่ม lambdas ซึ่งไม่สามารถพูดได้

auto sq = [](int x) {
    return x * x;
};
// there is no name for the type of sq

การอนุมานประเภทยังสนับสนุนแม่แบบ

template <class x_t>
auto sq(x_t const& x)
{
    return x * x;
}
// x_t is not known until it is inferred from an expression
sq(2); // x_t is int
sq(2.0); // x_t is double

แต่คำถามของคุณคือ "ทำไมฉัน, โปรแกรมเมอร์, ต้องการที่จะอนุมานประเภทของตัวแปรของฉันเมื่อฉันอ่านรหัสหรือไม่มันเร็วกว่าสำหรับทุกคนที่อ่านประเภทมากกว่าที่จะคิดว่ามีประเภทใด?"

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

std::vector<int> v;
std::vector<int>::iterator i = v.begin();

ไม่คุ้นเคยกับไลบรารีมาตรฐานสำหรับโปรแกรมเมอร์ C ++ เพื่อระบุว่า i เป็นตัววนซ้ำi = v.begin()ดังนั้นการประกาศชนิดที่ชัดเจนจึงมีค่า จำกัด การปรากฏตัวของมันจะปิดบังรายละเอียดที่สำคัญกว่า (เช่นiชี้ไปที่จุดเริ่มต้นของเวกเตอร์) คำตอบที่ดีโดย @amon ให้ตัวอย่างที่ดียิ่งขึ้นของการใช้คำฟุ่มเฟื่อยมากกว่ารายละเอียดที่สำคัญ ในทางตรงกันข้ามการใช้การอนุมานประเภทให้ความสำคัญกับรายละเอียดที่สำคัญมากขึ้น

std::vector<int> v;
auto i = v.begin();

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

std::vector<int> v;
std::vector<int>::iterator i = v.begin();

ในกรณีที่ฉันต้องเปลี่ยนประเภทค่าของเวกเตอร์เพื่อเปลี่ยนรหัสเป็นสองเท่า:

std::vector<double> v;
std::vector<double>::iterator i = v.begin();

ในกรณีนี้ฉันต้องแก้ไขโค้ดในที่สองแห่ง ตรงกันข้ามกับการอนุมานประเภทโดยที่รหัสต้นฉบับคือ:

std::vector<int> v;
auto i = v.begin();

และรหัสแก้ไข:

std::vector<double> v;
auto i = v.begin();

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

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

int pi = 3.14159;

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

int y = sq(x);

ในกรณีที่sq(x)ส่งกลับintก็ไม่ได้เป็นที่เห็นได้ชัดว่าyเป็นintเพราะมันเป็นชนิดที่การกลับมาของหรือเพราะมันเหมาะกับงบที่ใช้sq(x) yหากฉันเปลี่ยนรหัสอื่นซึ่งsq(x)ไม่ได้ผลตอบแทนอีกต่อไปintจะไม่แน่ใจจากบรรทัดนั้นเพียงอย่างเดียวว่าyควรปรับปรุงประเภทของ ตรงกันข้ามกับรหัสเดียวกัน แต่ใช้การอนุมานประเภท:

auto y = sq(x);

ในการนี้ความตั้งใจที่จะเป็นที่ชัดเจนจะต้องเป็นชนิดเดียวกันที่ส่งกลับโดยy sq(x)เมื่อรหัสเปลี่ยนประเภทการส่งคืนของsq(x)ประเภทyการเปลี่ยนแปลงจะจับคู่โดยอัตโนมัติ

ใน C ++ มีเหตุผลที่สองว่าทำไมตัวอย่างด้านบนนั้นง่ายกว่าด้วยการอนุมานประเภทการอนุมานประเภทไม่สามารถแนะนำการแปลงประเภทโดยนัย หากประเภทการกลับมาของsq(x)ไม่ได้คอมไพเลอร์กับเงียบแทรกแปลงนัยไปint intหากชนิดส่งคืนของsq(x)เป็นชนิดซับซ้อนชนิดที่กำหนดการoperator int()เรียกใช้ฟังก์ชันที่ซ่อนอยู่นี้อาจซับซ้อนอย่างไม่มีกฎเกณฑ์


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