ทำไมภาษาที่จำเป็น / OO ที่เป็นที่รู้จักกันดีส่วนใหญ่อนุญาตให้เข้าถึงประเภทที่สามารถแสดงถึงค่า 'ไม่มีอะไร' ได้โดยไม่ จำกัด


29

ผมได้อ่านเกี่ยวกับ (UN) ความสะดวกสบายของการมีnullแทน Maybe(ตัวอย่าง) หลังจากที่ได้อ่านบทความนี้ , ผมเชื่อว่ามันจะดีกว่าที่จะใช้Maybe (หรือบางสิ่งบางอย่างที่คล้ายกัน) อย่างไรก็ตามฉันรู้สึกประหลาดใจที่เห็นว่าภาษาการเขียนโปรแกรมเชิงวัตถุหรือเชิงวัตถุที่มีชื่อเสียง "ยังคงใช้อยู่null(ซึ่งอนุญาตการเข้าถึงชนิดที่ไม่ถูกตรวจสอบซึ่งสามารถแสดงถึงค่า 'ไม่มีอะไร') และMaybeส่วนใหญ่จะใช้ในภาษาโปรแกรมเชิงฟังก์ชัน

ตัวอย่างเช่นดูรหัส C # ต่อไปนี้:

void doSomething(string username)
{
    // Check that username is not null
    // Do something
}

มีบางอย่างมีกลิ่นไม่ดีที่นี่ ... ทำไมเราควรตรวจสอบว่าข้อโต้แย้งนั้นเป็นโมฆะหรือไม่ เราไม่ควรคิดว่าทุกตัวแปรมีการอ้างอิงไปยังวัตถุหรือไม่? อย่างที่คุณเห็นปัญหาคือว่าโดยนิยามตัวแปรเกือบทั้งหมดสามารถมีการอ้างอิงที่เป็นโมฆะ เกิดอะไรขึ้นถ้าเราสามารถตัดสินใจว่าตัวแปรใดเป็น "โมฆะ" และไม่ได้? นั่นจะช่วยเราได้มากในขณะที่ทำการดีบั๊กและมองหา "NullReferenceException" ลองจินตนาการว่าโดยค่าเริ่มต้นไม่มีประเภทอาจมีอ้างอิงโมฆะ แทนที่จะเป็นเช่นนั้นคุณจะระบุอย่างชัดเจนว่าตัวแปรสามารถมีการอ้างอิงที่เป็นโมฆะได้เฉพาะในกรณีที่คุณต้องการ นั่นคือความคิดเบื้องหลังบางที หากคุณมีฟังก์ชั่นที่ในบางกรณีล้มเหลว (ตัวอย่างเช่นการหารด้วยศูนย์) คุณสามารถส่งกลับMaybe<int>ระบุอย่างชัดเจนว่าผลลัพธ์อาจเป็น int แต่ยังไม่มีอะไร! นี่คือเหตุผลหนึ่งที่ต้องการบางทีอาจจะแทนที่จะเป็นโมฆะ หากคุณมีความสนใจในตัวอย่างมากขึ้นแล้วฉันขอแนะนำให้อ่านบทความนี้

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

  • สิ่งที่ชนิดของการขัดแย้งที่คุณจะมีการดำเนินการnullในการเขียนโปรแกรมภาษาของคุณแทนMaybe? มีเหตุผลทั้งหมดหรือว่าเป็น "สัมภาระประวัติศาสตร์" หรือไม่?

โปรดให้แน่ใจว่าคุณเข้าใจความแตกต่างระหว่าง null และอาจจะก่อนที่จะตอบคำถามนี้


3
ฉันขอแนะนำให้อ่านเกี่ยวกับTony Hoareโดยเฉพาะอย่างยิ่งความผิดพลาดพันล้านดอลลาร์ของเขา
Oded

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

9
สัมภาระในอดีตไม่ใช่สิ่งที่จะประมาท และจำไว้ว่าระบบปฏิบัติการที่สิ่งปลูกสร้างเหล่านี้เขียนด้วยภาษาที่มีnullอยู่เป็นเวลานาน มันไม่ง่ายเลยที่จะทำเช่นนั้น
Oded

3
ฉันคิดว่าคุณควรจะเข้าใจถึงแนวคิดของบางทีแทนที่จะโพสต์ลิงก์
JeffO

1
@ GlenH7 สตริงใน C # เป็นค่าอ้างอิง (อาจเป็นโมฆะ) ฉันรู้ว่า int เป็นค่าดั้งเดิม แต่มันก็มีประโยชน์ที่จะแสดงให้เห็นถึงการใช้งานของบางที
aochagavia

คำตอบ:


15

ฉันเชื่อว่าเป็นสัมภาระทางประวัติศาสตร์เป็นหลัก

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

ที่สองในบรรทัดมา Java เมื่อพิจารณาจากนักพัฒนา Java พยายามที่จะใกล้เคียงกับ C ++ มากขึ้นดังนั้นพวกเขาจึงสามารถเปลี่ยนจาก C ++ เป็น Java ได้ง่ายขึ้นพวกเขาอาจไม่ต้องการยุ่งกับแนวคิดหลักของภาษา นอกจากนี้การใช้งานอย่างชัดเจนnullจะต้องใช้ความพยายามมากขึ้นเพราะคุณต้องตรวจสอบว่าการอ้างอิงที่ไม่ใช่ค่า Null ถูกตั้งค่าอย่างถูกต้องหลังจากการเริ่มต้น

ภาษาอื่น ๆ ทั้งหมดเช่นเดียวกับ Java พวกเขามักจะคัดลอกวิธีการ C ++ หรือ Java ไม่ได้และพิจารณาว่าแนวคิดหลักของนัยประเภทอ้างอิงมันจะกลายเป็นเรื่องยากที่จะออกแบบภาษาที่ใช้ที่ชัดเจนnullnull


“ พวกเขาอาจไม่ต้องการยุ่งกับแนวคิดหลักของภาษานี้” พวกเขาลบพอยน์เตอร์ออกไปอย่างสมบูรณ์แล้วการลบออกnullก็ไม่ได้เป็นการเปลี่ยนแปลงครั้งใหญ่เลย
svick

2
@svick สำหรับ Java การอ้างอิงจะถูกแทนที่สำหรับพอยน์เตอร์ และในหลายกรณีมีการใช้พอยน์เตอร์ใน C ++ ในลักษณะเดียวกับการอ้างอิง Java บางคนอ้างว่า Java มีพอยน์เตอร์ ( programmers.stackexchange.com/questions/207196/ … )
Euphoric

ฉันทำเครื่องหมายว่านี่เป็นคำตอบที่ถูกต้อง ฉันต้องการถอนรากถอนโคน แต่ฉันมีชื่อเสียงไม่เพียงพอ
aochagavia

1
ตกลง. โปรดทราบว่าใน C ++ (ซึ่งแตกต่างจาก Java และ C) การเป็นโมฆะสามารถเป็นข้อยกเว้น ไม่สามารถstd::string ไม่สามารถ กระป๋องและ C ++ ช่วยให้สามารถเข้าถึงได้ตรวจสอบไปด้วยเหตุผลสองประการคือ 1. เพราะ C ได้และ 2. เพราะคุณควรจะเข้าใจสิ่งที่คุณกำลังทำเมื่อใช้ตัวชี้ดิบใน C ++ nullint&nullint*
MSalters

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

15

ที่จริงแล้วnullเป็นความคิดที่ดี ให้ตัวชี้เราต้องการกำหนดว่าตัวชี้นี้ไม่ได้อ้างอิงค่าที่ถูกต้อง ดังนั้นเราจึงใช้สถานที่หนึ่งในหน่วยความจำประกาศว่ามันไม่ถูกต้องและยึดตามการประชุมนั้น (บางครั้งการประชุมบังคับใช้กับ segfaults) ตอนนี้เมื่อใดก็ตามที่ฉันมีพอยน์เตอร์ฉันสามารถตรวจสอบว่ามีNothing( ptr == null) หรือSome(value)( ptr != null, value = *ptr) หรือไม่ ฉันต้องการให้คุณเข้าใจว่านี่เทียบเท่ากับMaybeประเภท

ปัญหานี้คือ:

  1. ในหลายภาษาระบบประเภทไม่ช่วยที่นี่เพื่อรับประกันการอ้างอิงที่ไม่เป็นโมฆะ

    นี่คือสัมภาระในอดีตเนื่องจากความจำเป็นหลัก ๆ หรือภาษา OOP มีความก้าวหน้าที่เพิ่มขึ้นในระบบการพิมพ์ของพวกเขาเมื่อเปรียบเทียบกับรุ่นก่อน การเปลี่ยนแปลงเล็กน้อยมีข้อได้เปรียบที่ภาษาใหม่ง่ายต่อการเรียนรู้ C # เป็นภาษากระแสหลักที่ได้แนะนำเครื่องมือระดับภาษาเพื่อจัดการกับค่า null ได้ดีขึ้น

  2. นักออกแบบ API อาจกลับมาnullล้มเหลว แต่ไม่ใช่การอ้างอิงถึงสิ่งที่เกิดขึ้นจริงในความสำเร็จ บ่อยครั้งสิ่งที่ (ไม่มีการอ้างอิง) จะถูกส่งกลับโดยตรง การแบนของระดับตัวชี้นี้ทำให้ไม่สามารถใช้nullเป็นค่าได้

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

  3. ใน Haskell มีมุมมองที่เรียบร้อยสำหรับMaybeประเภท monad สิ่งนี้ทำให้ง่ายต่อการเขียนการแปลงค่าที่มีอยู่

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


“ C # กำลังดำเนินการห่างจากการอ้างอิงที่เป็นโมฆะ” มีขั้นตอนอะไรบ้าง ฉันไม่ได้เห็นอะไรแบบนั้นในการเปลี่ยนแปลงภาษา หรือคุณหมายถึงว่าห้องสมุดทั่วไปใช้nullน้อยกว่าที่เคยทำในอดีต?
svick

@svick ใช้ถ้อยคำที่ไม่ดีในส่วนของฉัน “ C # เป็นภาษาหลักที่ได้แนะนำเครื่องมือภาษาระดับการจัดการที่ดีnulls ” - ฉันกำลังพูดคุยเกี่ยวกับNullableประเภทและ??ผู้ประกอบการเริ่มต้น มันไม่สามารถแก้ปัญหาได้ในขณะนี้หากมีรหัสเดิม แต่มันเป็นก้าวต่อไปในอนาคตที่ดีกว่า
amon

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

1
@svick Nullable ไม่มีส่วนเกี่ยวข้องกับสิ่งนี้ เรากำลังพูดถึงประเภทการอ้างอิงทั้งหมดโดยปริยายอนุญาตให้มีค่า Null แทนที่จะให้โปรแกรมเมอร์กำหนดไว้อย่างชัดเจน และ Nullable สามารถใช้ได้กับประเภทค่าเท่านั้น
ร่าเริง

@Euphoric Nullableผมคิดว่าความคิดเห็นของคุณมีความหมายเป็นการตอบกลับอมรผมไม่ได้พูดถึง
svick

9

ความเข้าใจของฉันเป็นnullสิ่งที่จำเป็นในการสร้างภาษาการเขียนโปรแกรมเชิงนามธรรมออกจากการชุมนุม 1 โปรแกรมเมอร์ต้องการความสามารถในการระบุว่าตัวชี้หรือค่าการลงทะเบียนเป็นnot a valid valueและnullกลายเป็นคำทั่วไปสำหรับความหมายนั้น

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

หากคุณกำลังออกแบบภาษาใหม่และต้องการหลีกเลี่ยงnullแต่ใช้maybeแทนฉันจะสนับสนุนคำที่อธิบายเพิ่มเติมเช่นnot a valid valueหรือnavvเพื่อระบุเจตนา แต่ชื่อของค่าที่ไม่ได้เป็นแนวคิดที่แยกต่างหากจากว่าคุณควรอนุญาตให้มีค่าที่ไม่ใช่อยู่ในภาษาของคุณ

ก่อนที่คุณจะสามารถตัดสินใจเลือกได้สองจุดคุณต้องกำหนดความmaybeหมายของระบบของคุณ คุณอาจพบว่ามันเป็นเพียงการเปลี่ยนชื่อnullความหมายของnot a valid valueหรือคุณอาจพบว่ามันมีความหมายแตกต่างกันสำหรับภาษาของคุณ

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

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

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

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

ดังนั้นเพื่อตอบคำถามของคุณ:

  1. "การโต้เถียงแบบไหนกัน ... " - ก็ขึ้นอยู่กับว่าคุณต้องการให้ภาษาทำอะไร หากคุณต้องการจำลองการเข้าถึงโลหะเปลือยคุณอาจต้องอนุญาต

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


1 ดูบทความ Wikipedia นี้แม้ว่าจะให้เครดิตแก่ Hoare สำหรับค่า Null และภาษาเชิงวัตถุ ฉันเชื่อว่าภาษาที่จำเป็นก้าวหน้าไปตามลำดับวงศ์ตระกูลที่แตกต่างจากที่ Algol ทำ


ประเด็นก็คือตัวแปรส่วนใหญ่ใน, พูด, C # หรือ Java, สามารถกำหนดอ้างอิงเป็นโมฆะ ดูเหมือนว่าจะเป็นการดีกว่ามากในการกำหนดการอ้างอิงแบบ null ให้กับวัตถุที่ระบุอย่างชัดเจนว่า "อาจ" ไม่มีการอ้างอิง ดังนั้นคำถามของฉันเกี่ยวกับ "แนวคิด" เป็นโมฆะไม่ใช่คำว่า
aochagavia

2
“ การอ้างอิงตัวชี้ Null สามารถแสดงเป็นข้อผิดพลาดระหว่างการคอมไพล์” คอมไพเลอร์ตัวใดที่สามารถทำได้?
svick

เพื่อความเป็นธรรมอย่างสมบูรณ์คุณไม่เคยกำหนดการอ้างอิงที่เป็นโมฆะให้กับวัตถุ ... การอ้างอิงไปยังวัตถุนั้นไม่มีอยู่ (การอ้างอิงชี้ไปที่ไม่มีอะไร (0x000000000) ซึ่งเป็นไปตามข้อกำหนดnull)
mgw854

ราคาอ้างอิงของสเปค C99 พูดถึงตัวละครโมฆะไม่ใช่ตัวชี้โมฆะนี่เป็นแนวคิดที่แตกต่างกันสองอย่าง
svick

2
@ GlenH7 มันไม่ได้ทำเพื่อฉัน รหัสobject o = null; o.ToString();รวบรวมได้ดีสำหรับฉันโดยไม่มีข้อผิดพลาดหรือคำเตือนใน VS2012 ReSharper บ่นเกี่ยวกับเรื่องนั้น แต่นั่นไม่ใช่คอมไพเลอร์
svick

7

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

หมายเหตุฉันพูดว่า "เตือน" ไม่บังคับ โปรแกรมเมอร์ขี้เกียจ หากโปรแกรมเมอร์ไม่สามารถมั่นใจได้ว่าค่านั้นเป็นไปได้NothingพวกเขาจะทำการMaybeตรวจสอบซ้ำโดยไม่ตรวจสอบเช่นเดียวกับที่พวกเขาทำการยกเลิกตัวชี้โมฆะทันที ผลลัพธ์ที่ได้คือคุณแปลงข้อยกเว้นตัวชี้ null เป็นข้อยกเว้น "dereferenced empty อาจ"

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

สิ่งที่ทำให้Maybeดีคือเมื่อทำการตัดสินใจจำนวนมากผ่านการจับคู่รูปแบบและ polymorphism แทนการตรวจสอบที่ชัดเจน ตัวอย่างเช่นคุณสามารถสร้างฟังก์ชั่นที่แยกต่างหากprocessData(Some<T>)และที่คุณไม่สามารถทำอะไรกับprocessData(Nothing<T>) nullคุณย้ายการจัดการข้อผิดพลาดของคุณไปยังฟังก์ชั่นแยกต่างหากโดยอัตโนมัติซึ่งเป็นที่ต้องการอย่างมากในฟังก์ชั่นการเขียนโปรแกรมที่ฟังก์ชั่นถูกส่งผ่านไปรอบ ๆ และประเมินผลอย่างเกียจคร้าน ใน OOP วิธีที่แนะนำในการแยกรหัสการจัดการข้อผิดพลาดของคุณคือการยกเว้น


คุณคิดว่ามันจะเป็นคุณสมบัติที่ต้องการในภาษา OO ใหม่หรือไม่?
aochagavia

คุณสามารถใช้มันด้วยตัวคุณเองหากคุณต้องการได้รับผลประโยชน์ที่หลากหลาย สิ่งเดียวที่คุณต้องการการสนับสนุนด้านภาษาคือความไม่เป็นโมฆะ ฉันชอบที่จะเห็นวิธีการระบุว่าสำหรับตัวเองคล้ายกับconstแต่ทำให้มันเป็นตัวเลือก โค้ดระดับล่างบางประเภทเช่นรายการที่ลิงก์จะน่ารำคาญมากที่จะนำไปใช้กับออบเจ็กต์ที่ไม่เป็นโมฆะ
Karl Bielefeldt

2
คุณไม่ต้องตรวจสอบด้วยอาจพิมพ์ พิมพ์อาจเป็น monad ดังนั้นควรมีฟังก์ชั่นmap :: Maybe a -> (a -> b) และbind :: Maybe a -> (a -> Maybe b)กำหนดไว้เพื่อให้คุณสามารถดำเนินการต่อและเธรดการคำนวณเพิ่มเติมสำหรับส่วนใหญ่ด้วยการใช้คำสั่ง if else และgetValueOrDefault :: Maybe a -> (() -> a) -> aช่วยให้คุณจัดการกับกรณีที่เป็นโมฆะ มันดูหรูหรากว่าการจับคู่รูปแบบในแบบMaybe aชัดแจ้ง
DetriusXii

1

Maybeเป็นวิธีที่ใช้งานได้ดีในการคิดปัญหา - มีบางสิ่งและอาจมีหรือไม่มีค่าที่กำหนดไว้ อย่างไรก็ตามในแง่ของวัตถุเราเปลี่ยนความคิดของสิ่งนั้น (ไม่ว่าจะมีคุณค่าหรือไม่ก็ตาม) ด้วยวัตถุ เห็นได้ชัดว่าวัตถุมีค่า หากไม่เป็นเช่นนั้นเราก็บอกว่าวัตถุนั้นเป็นnullแต่สิ่งที่เราหมายถึงจริงๆก็คือไม่มีวัตถุใด ๆ เลย การอ้างอิงที่เรามีกับวัตถุนั้นชี้ไปที่อะไร การแปลMaybeเป็นแนวคิด OO นั้นไม่ได้แปลกอะไรเลยจริง ๆ แล้วมันทำให้รหัสที่ยุ่งเหยิงยิ่งขึ้น คุณยังต้องมีการอ้างอิงแบบ null สำหรับค่าของMaybe<T>. คุณยังต้องทำการตรวจสอบโมฆะ (ในความเป็นจริงคุณต้องทำการตรวจสอบโมฆะเพิ่มเติมอีกมากมายทำให้รหัสของคุณยุ่งเหยิง) แม้ว่าตอนนี้พวกเขาจะถูกเรียกว่า "อาจตรวจสอบ" แน่นอนว่าคุณจะเขียนโค้ดที่มีประสิทธิภาพมากขึ้นตามที่ผู้เขียนอ้าง แต่ฉันยืนยันว่ามันเป็นเพียงกรณีเพราะคุณได้สร้างภาษาที่เป็นนามธรรมและป้านมากขึ้นต้องใช้งานในระดับที่ไม่จำเป็นในกรณีส่วนใหญ่ ฉันยินดีที่จะใช้ NullReferenceException นาน ๆ กว่าจัดการกับรหัสสปาเก็ตตี้ทำอาจจะตรวจสอบทุกครั้งที่ฉันเข้าถึงตัวแปรใหม่


2
ฉันคิดว่ามันจะนำไปสู่การตรวจสอบโมฆะน้อยเพราะคุณจะต้องตรวจสอบว่าคุณเห็นบางที <T> และไม่ต้องกังวลเกี่ยวกับประเภทที่เหลือ
aochagavia

1
@svick Maybe<T>ต้องอนุญาตnullเป็นค่าเนื่องจากอาจไม่มีค่า หากฉันมีMaybe<MyClass>และไม่มีค่าฟิลด์ค่าต้องมีการอ้างอิงที่เป็นโมฆะ ไม่มีอะไรอีกแล้วที่จะปลอดภัย
mgw854

1
@ mgw854 แน่นอนว่ามี ในภาษา OO Maybeอาจเป็นคลาสนามธรรมโดยมีสองคลาสที่สืบทอดจากคลาสนั้น: Some(ซึ่งมีฟิลด์สำหรับค่า) และNone(ซึ่งไม่มีฟิลด์นั้น) nullวิธีการที่มีค่าเป็นไม่เคย
svick

6
ด้วยค่าเริ่มต้น "ไม่เป็นโมฆะ" และบางที <T> คุณอาจมั่นใจได้ว่าตัวแปรบางตัวมีวัตถุอยู่เสมอ กล่าวคือตัวแปรทั้งหมดที่ไม่ใช่ <T>
aochagavia

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

1

แนวคิดของnullสามารถย้อนกลับไปที่ C ได้อย่างง่ายดาย แต่นั่นไม่ใช่ปัญหาที่เกิดขึ้น

ภาษาที่เลือกในชีวิตประจำวันของฉันคือ C # และฉันจะเก็บไว้nullกับหนึ่งความแตกต่าง C # มีสองชนิดชนิด, ค่าและการอ้างอิง คุณค่าไม่สามารถเป็นไปได้nullแต่มีหลายครั้งที่ฉันต้องการแสดงว่าไม่มีค่าใดที่สมบูรณ์แบบ การทำเช่นนี้ C # ใช้Nullableประเภทดังนั้นintจะเป็นค่าและint?ค่า nullable นี่คือวิธีที่ฉันคิดว่าประเภทการอ้างอิงควรทำงานได้เช่นกัน

ดูเพิ่มเติมที่: การอ้างอิงที่ว่างเปล่าอาจไม่ใช่ความผิดพลาด :

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


0

ฉันคิดว่าเป็นเพราะการเขียนโปรแกรมใช้งานมีความกังวลมากเกี่ยวกับประเภทโดยเฉพาะประเภทที่รวมประเภทอื่น ๆ (tuples, ฟังก์ชั่นเป็นประเภทชั้นแรก, monads, ฯลฯ ) กว่าการเขียนโปรแกรมเชิงวัตถุ (หรืออย่างน้อยก็เริ่ม)

ฉันคิดว่าคุณกำลังพูดถึงภาษาโปรแกรมในปัจจุบัน (C ++, C #, Java) ล้วน แต่ใช้ภาษาที่ไม่มีการเขียนโปรแกรมทั่วไป (C, C # 1.0, Java 1) หากไม่มีสิ่งนั้นคุณยังสามารถอบความแตกต่างบางอย่างระหว่างออบเจ็กต์ nullable และ non-nullable ลงในภาษา (เช่นการอ้างอิง C ++ ซึ่งไม่สามารถทำได้nullแต่ยังมีข้อ จำกัด ) แต่มันก็เป็นธรรมชาติน้อยกว่ามาก


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

0

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

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


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

1
@gnat: ดีกว่าเหรอ?
supercat

0

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

คุณสามารถใช้งานบางทีกับภาษาที่มีค่าว่างได้อย่างง่ายดาย C ++ boost::optional<T>มีหนึ่งในรูปแบบของ การทำสิ่งที่เทียบเท่ากับ null ด้วยบางทีอาจเป็นเรื่องยากมาก โดยเฉพาะอย่างยิ่งถ้าฉันมีMaybe<Just<T>>ฉันไม่สามารถกำหนดให้เป็นโมฆะ (เนื่องจากแนวคิดดังกล่าวไม่มีอยู่) ในขณะที่T**ภาษาที่มีค่า null นั้นง่ายมากที่จะกำหนดให้เป็นค่าว่าง สิ่งนี้บังคับให้ใช้Maybe<Maybe<T>>ซึ่งใช้ได้อย่างสมบูรณ์ แต่จะบังคับให้คุณทำการตรวจสอบอื่น ๆ อีกมากมายเพื่อใช้วัตถุนั้น

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

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