การพิมพ์สแตติกมีประโยชน์จริง ๆ ในโครงการขนาดใหญ่อย่างไร


9

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

เมื่อระบบมีขนาดใหญ่เกินไปที่จะเก็บไว้ในหัวของคุณคุณสามารถเพิ่มประเภทคงที่

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

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

นอกจากนี้เมื่อฟังก์ชั่นถูกประกาศด้วยการtype funcname()...รู้ทันtypeคุณจะต้องค้นหาแต่ละบรรทัดที่เรียกใช้ฟังก์ชั่นเพราะคุณรู้เพียงว่าfuncnameในขณะที่ในไพ ธ อนและสิ่งที่คุณชอบเพียงแค่ค้นหาdef funcnameหรือfunction funcnameเกิดขึ้นเพียงครั้งเดียวที่ การประกาศ

ยิ่งกว่านั้นด้วย REPLs การทดสอบฟังก์ชั่นการกลับมาของอินพุตที่แตกต่างกันเล็กน้อยในขณะที่ภาษาที่พิมพ์แบบคงที่คุณจะต้องเพิ่มโค้ดบางบรรทัด

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



2
ถ้าคุณอ่านคำตอบของคำถามอื่น ๆ ที่คุณอาจจะได้คำตอบที่คุณต้องการสำหรับหนึ่งนี้พวกเขามีพื้นถามในสิ่งเดียวกันจากมุมมองที่แตกต่างกัน :)
sara

1
Swift และ playgrounds เป็น REPL ของภาษาที่พิมพ์แบบคงที่
daven11

2
ภาษาไม่ได้ถูกคอมไพล์ วิธีการเขียน REPL สำหรับภาษา "รวบรวม" คือการเขียนสิ่งที่สามารถแปลภาษาหรืออย่างน้อยก็รวบรวมและดำเนินการมันทีละบรรทัดโดยรักษาสถานะที่จำเป็นรอบ ๆ นอกจากนี้ Java 9 จะมาพร้อมกับ REPL
Sebastian Redl

2
@ user6245072: นี่คือวิธีการสร้าง REPL สำหรับล่าม: อ่านรหัสส่งไปที่ล่ามพิมพ์ผลลัพธ์ ต่อไปนี้เป็นวิธีสร้าง REPL สำหรับคอมไพเลอร์: อ่านโค้ดส่งไปยังคอมไพเลอร์เรียกใช้โค้ดที่คอมไพล์แล้วพิมพ์ผลลัพธ์ ง่ายเหมือนพาย นั่นคือสิ่งที่ FSi (F♯ REPL) GHCi (GHC Haskell's REPL) Scala REPL และ Cling ทำ
Jörg W Mittag

คำตอบ:


21

ยิ่งกว่านั้นด้วย REPLs มันเป็นการทดสอบฟังก์ชั่นการกลับมาของมันด้วยอินพุตที่แตกต่างกันเล็กน้อย

มันไม่สำคัญเลย มันไม่ได้เล็ก ๆ น้อย ๆที่ทุกคน มันเป็นเพียงเรื่องเล็กน้อยที่จะทำเช่นนี้สำหรับฟังก์ชั่นเล็กน้อย

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

getAnswer(v) {
 return v.answer
}

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

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

getAnswer(x, y) {
   if (x + y.answer == 13)
       return 1;
   return "1";
}

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

นอกจากนี้เมื่อฟังก์ชั่นถูกประกาศด้วยประเภท funcname () ... , การรู้น้อยประเภทที่คุณจะต้องค้นหาในแต่ละบรรทัดที่เรียกว่าฟังก์ชั่นเพราะคุณรู้เพียง funcname ในขณะที่ในงูหลามและชอบที่คุณดัง ค้นหา def funcname หรือ function funcname ซึ่งเกิดขึ้นเพียงครั้งเดียวที่การประกาศ

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

จากหน่วยความจำdef funcnameจะไม่เพียงพอใน Python เนื่องจากฟังก์ชั่นสามารถกำหนดใหม่ได้โดยพลการ หรือสามารถประกาศซ้ำ ๆ ในหลายโมดูล หรือในชั้นเรียน เป็นต้น

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

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


2
เพื่อความเป็นธรรม "เครื่องมือ" เหล่านั้นถูกประดิษฐ์ในภาษาแบบไดนามิกและภาษาแบบไดนามิกมีมานานก่อนที่ภาษาแบบคงที่จะทำ ไปที่คำจำกัดความการเติมโค้ดให้สมบูรณ์การรีแฟคเตอร์แบบอัตโนมัติ ฯลฯ มีอยู่ใน Lisp แบบกราฟิกและ Smalltalk IDEs ก่อนที่ภาษาแบบคงที่จะมีกราฟิกหรือ IDE
Jörg W Mittag

รู้ชนิดกลับของฟังก์ชั่นไม่เคยบอกคุณว่าฟังก์ชั่นDO แทนที่จะเขียนประเภทคุณสามารถทดสอบการเขียนเอกสารด้วยค่าตัวอย่าง ตัวอย่างเช่นเปรียบเทียบ (คำว่า 'some words oue') => ['some', 'words', 'oeu'] กับ (สตริงคำ) -> [string], (zip {abc} [1..3]) => [(a, 1), (b, 2), (c, 3)] ด้วยประเภทของมัน
aoeu256

18

นึกถึงโปรเจ็กต์ที่มีโปรแกรมเมอร์จำนวนมากที่เปลี่ยนแปลงไปหลายปี คุณต้องดูแลสิ่งนี้ มีฟังก์ชั่น

getAnswer(v) {
 return v.answer
}

มันทำอะไรบนโลก? อะไรนะv? องค์ประกอบanswerมาจากไหน

getAnswer(v : AnswerBot) {
  return v.answer
}

ตอนนี้เรามีข้อมูลเพิ่มเติม -; AnswerBotมันต้องการประเภทของ

ถ้าเราไปเป็นภาษาที่ใช้ในห้องเรียน

class AnswerBot {
  var answer : String
  func getAnswer() -> String {
    return answer
  }
}

ตอนนี้เรามีตัวแปรชนิดAnswerBotแล้วเรียกเมธอดgetAnswerและทุกคนรู้ว่ามันทำอะไร การเปลี่ยนแปลงใด ๆ ที่รวบรวมโดยคอมไพเลอร์ก่อนที่จะทำการทดสอบรันไทม์ใด ๆ มีตัวอย่างอื่น ๆ อีกมากมาย แต่บางทีนี่อาจช่วยให้คุณมีความคิด?


1
ดูชัดเจนขึ้น - ถ้าคุณชี้ให้เห็นว่าฟังก์ชั่นแบบนั้นไม่มีเหตุผลอยู่จริงแน่นอนว่าเป็นเพียงตัวอย่าง
user6245072

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

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

3
"ฟังก์ชั่นในภาษาไดนามิกเป็นค่าเริ่มต้นในเนมสเปซส่วนกลาง" นี่เป็นรายละเอียดเฉพาะภาษาไม่ใช่ข้อ จำกัด ที่เกิดจากการพิมพ์แบบไดนามิก
sara

2
@ daven11 "ฉันคิดว่าจาวาสคริปต์ที่นี่" แต่ภาษาไดนามิกอื่น ๆ มีเนมสเปซ / โมดูล / แพ็คเกจจริงและสามารถเตือนคุณเกี่ยวกับการกำหนดใหม่ คุณอาจจะพูดเกินจริงไปสักหน่อย
coredump

10

คุณดูเหมือนจะมีความเข้าใจผิดบางประการเกี่ยวกับการทำงานกับโครงการคงที่ขนาดใหญ่ที่อาจทำให้การตัดสินใจของคุณขุ่นมัว นี่คือตัวชี้:

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

คนส่วนใหญ่ที่ทำงานกับภาษาที่พิมพ์แบบสแตติกใช้ IDE สำหรับภาษาหรือโปรแกรมแก้ไขอัจฉริยะ (เช่น vim หรือ emacs) ที่มีการทำงานร่วมกับเครื่องมือเฉพาะภาษา มักจะมีวิธีที่รวดเร็วในการค้นหาประเภทของฟังก์ชันในเครื่องมือเหล่านี้ ตัวอย่างเช่นเมื่อใช้ Eclipse บนโปรเจ็กต์ Java มีสองวิธีที่คุณมักจะพบกับชนิดของเมธอด:

  • หากฉันต้องการใช้วิธีการกับวัตถุอื่นที่ไม่ใช่ 'this' ฉันจะพิมพ์การอ้างอิงและจุด (เช่นsomeVariable.) และ Eclipse ค้นหาชนิดของsomeVariableและให้รายการแบบหล่นลงของวิธีการทั้งหมดที่กำหนดในประเภทนั้น ขณะที่ฉันเลื่อนรายการประเภทและเอกสารของแต่ละรายการจะปรากฏขึ้นขณะที่เลือก โปรดทราบว่านี่เป็นเรื่องยากมากที่จะประสบความสำเร็จด้วยภาษาแบบไดนามิกเนื่องจากเป็นเรื่องยาก (หรือในบางกรณีเป็นไปไม่ได้) สำหรับตัวแก้ไขเพื่อกำหนดประเภทของsomeVariableดังนั้นจึงไม่สามารถสร้างรายการที่ถูกต้องได้อย่างง่ายดาย ถ้าฉันต้องการใช้วิธีการthisฉันสามารถกด ctrl + space เพื่อรับรายการเดียวกัน (แม้ว่าในกรณีนี้มันไม่ยากเลยที่จะประสบความสำเร็จสำหรับภาษาแบบไดนามิก)
  • หากฉันมีการอ้างอิงที่เขียนไปยังวิธีการเฉพาะฉันสามารถย้ายเคอร์เซอร์ของเมาส์เหนือมันและประเภทและเอกสารสำหรับวิธีการนั้นจะปรากฏในเคล็ดลับเครื่องมือ

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

นอกจากนี้เมื่อฟังก์ชั่นถูกประกาศด้วยประเภท funcname () ... , การรู้น้อยประเภทที่คุณจะต้องค้นหาในแต่ละบรรทัดที่เรียกว่าฟังก์ชั่นเพราะคุณรู้เพียง funcname ในขณะที่ในงูหลามและชอบที่คุณดัง ค้นหา def funcname หรือ function funcname ซึ่งเกิดขึ้นเพียงครั้งเดียวที่การประกาศ

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

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

ยิ่งกว่านั้นด้วย REPLs มันเป็นการทดสอบฟังก์ชั่นการกลับมาของมันด้วยอินพุตที่แตกต่างกันเล็กน้อย

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

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

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


4
You seem to have a few misconceptions about working with large static projects that may be clouding your judgement.ดีฉันอายุ 14 ปีและฉันเพียงโปรแกรมจากน้อยกว่าหนึ่งปีบน Android ดังนั้นจึงเป็นไปได้ที่ฉันเดา
user6245072

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

6
  1. เพราะตัวตรวจสอบแบบคงที่ง่ายกว่าสำหรับภาษาที่พิมพ์แบบคงที่
    • อย่างน้อยที่สุดโดยไม่มีฟีเจอร์ภาษาแบบไดนามิกถ้าคอมไพล์แล้วตอนรันไทม์ไม่มีฟังก์ชั่นที่ยังไม่ได้แก้ไข นี่เป็นเรื่องปกติในโครงการ ADA และ C ในไมโครคอนโทรลเลอร์ (โปรแกรมไมโครคอนโทรลเลอร์มีขนาดใหญ่ขึ้นในบางครั้ง ... เหมือนหลายร้อย kloc ใหญ่)
  2. การตรวจสอบการอ้างอิงแบบคอมไพล์แบบคงที่เป็นส่วนย่อยของค่าคงที่ของฟังก์ชันซึ่งในภาษาสแตติกสามารถตรวจสอบได้ในเวลาคอมไพล์
  3. ภาษาแบบคงที่มักจะมีความโปร่งใสในการอ้างอิง ผลลัพธ์ก็คือผู้พัฒนาใหม่สามารถดำน้ำในไฟล์เดียวและเข้าใจสิ่งที่เกิดขึ้นและแก้ไขข้อผิดพลาดหรือเพิ่มคุณสมบัติเล็ก ๆ โดยไม่ต้องรู้สิ่งแปลกประหลาดทั้งหมดใน codebase

เปรียบเทียบกับ say, javascript, Ruby หรือ Smalltalk ที่ผู้พัฒนาทำหน้าที่กำหนดภาษาหลักในเวลาทำงาน สิ่งนี้ทำให้การเข้าใจโครงการขนาดใหญ่ยากขึ้น

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

Anecdotally คนรู้จักของฉันมีการเขียนโปรแกรม "Job For Life" ที่ปลอดภัยใน Lisp ไม่มีใครยกเว้นทีมที่สามารถเข้าใจรหัสฐานได้


Anecdotally, an acquaintance of mine has a secure "Job For Life" programming in Lisp. Nobody except the team can understand the code-base.มันแย่ขนาดนั้นจริงเหรอ? การตั้งค่าส่วนบุคคลที่พวกเขาเพิ่มเข้ามาไม่ได้ช่วยให้พวกเขามีประสิทธิผลมากขึ้นหรือไม่
user6245072

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

คุณไม่สามารถใช้เครื่องมือติดตามเพื่อสร้างการทดสอบหน่วยจากโปรแกรม Lisp ที่กำลังทำงานอยู่หรือไม่ เช่นเดียวกับใน Python คุณสามารถสร้างมัณฑนากร (adverb) ชื่อ print_args ที่รับฟังก์ชั่นและส่งกลับฟังก์ชั่นที่ปรับเปลี่ยนซึ่งพิมพ์อาร์กิวเมนต์ของมัน จากนั้นคุณสามารถนำไปใช้กับโปรแกรมทั้งหมดใน sys.modules แม้ว่าวิธีที่ง่ายกว่าคือการใช้ sys.set_trace
aoeu256

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

@TimWilliscroft คุณสามารถรอจนกว่าแมโครทั้งหมดจะถูกขยายก่อนที่จะทำสิ่งนั้น Emacs มีปุ่มลัดจำนวนมากเพื่อให้คุณสามารถขยายมาโครแบบอินไลน์ได้ (และอาจมีฟังก์ชั่นอินไลน์)
aoeu256

4

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

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

นอกจากนี้เมื่อมีการประกาศฟังก์ชั่นด้วยประเภทการfuncname()...รู้รอบประเภทคุณจะต้องค้นหาแต่ละบรรทัดที่เรียกใช้ฟังก์ชั่นเพราะคุณรู้เพียงว่าfuncnameในขณะที่ใน Python และสิ่งที่คล้ายกันคุณสามารถค้นหาdef funcnameหรือfunction funcnameเกิดขึ้นเพียงครั้งเดียว ที่ประกาศ

นี่เป็นเรื่องของไวยากรณ์ซึ่งไม่เกี่ยวข้องอย่างสมบูรณ์จากการพิมพ์แบบคงที่

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

fn funcname(a: i32) -> i32

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

สามารถตีความภาษาใดก็ได้และภาษาใดก็ได้ที่มี REPL


ดังนั้นนอกเหนือจากการทราบประเภทการคืนค่าของฟังก์ชันที่เห็นได้ชัดว่าไม่ใช่จุดแข็งของภาษาที่พิมพ์แบบคงที่การพิมพ์แบบคงที่มีประโยชน์มากในโครงการขนาดใหญ่อย่างไร

ฉันจะตอบอย่างเป็นนามธรรม

โปรแกรมประกอบด้วยการดำเนินการต่าง ๆ และการดำเนินการเหล่านั้นถูกจัดวางในแบบที่เป็นเพราะสมมติฐานบางอย่างที่ผู้พัฒนาสร้างขึ้น

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

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

ฉันต้องการจัดหมวดหมู่สมมติฐานเป็นสองประเภท

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

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

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

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

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

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


3

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

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

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


คุณไม่จำเป็นต้องทำการอนุมานแบบสแตติก (pylint) คุณสามารถทำการอนุมานประเภทแบบไดนามิกchrislaffra.blogspot.com 2016/12/30ซึ่งทำโดยคอมไพเลอร์ JIT ของ PyPy นอกจากนี้ยังมีการอนุมานประเภทไดนามิกอีกรุ่นหนึ่งที่คอมพิวเตอร์สุ่มวางวัตถุจำลองในอาร์กิวเมนต์และดูสิ่งที่ทำให้เกิดข้อผิดพลาด ปัญหาการหยุดไม่สำคัญสำหรับ 99% ของกรณีหากคุณใช้เวลามากเกินไปในการหยุดอัลกอริทึม (นี่คือวิธีที่ Python จัดการการเรียกซ้ำแบบไม่สิ้นสุดมีการ จำกัด การเรียกซ้ำที่สามารถตั้งค่าได้)
aoeu256
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.