ประโยชน์ของการมี "ไม่มีข้อยกเว้นรันไทม์" เช่น Elm เรียกร้องคืออะไร?


16

บางภาษาอ้างว่ามี "ไม่มีข้อยกเว้นสำหรับรันไทม์" เพื่อเป็นข้อได้เปรียบที่ชัดเจนกว่าภาษาอื่น ๆ ที่มี

ฉันสับสนในเรื่องนี้

ข้อยกเว้นรันไทม์เป็นเพียงเครื่องมือเท่าที่ฉันรู้และเมื่อใช้กัน:

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

ในทางกลับกันฉันพบว่ายากที่จะดีบักซอฟต์แวร์ที่ "กลืน" ข้อยกเว้น เช่น

try { 
  myFailingCode(); 
} catch {
  // no logs, no crashes, just a dirty state
}

ดังนั้นคำถามก็คืออะไรคือความได้เปรียบเชิงทฤษฎีที่แข็งแกร่งของการมี "ไม่มีข้อยกเว้นรันไทม์"?


ตัวอย่าง

https://guide.elm-lang.org/

ไม่มีข้อผิดพลาดรันไทม์ในทางปฏิบัติ ไม่มีค่าว่าง ไม่มีการกำหนดไม่ได้เป็นฟังก์ชั่น


ฉันคิดว่ามันจะช่วยให้มีตัวอย่างหนึ่งหรือสองภาษาที่คุณอ้างถึงและ / หรือลิงก์ไปยังการอ้างสิทธิ์ดังกล่าว สิ่งนี้สามารถตีความได้หลายวิธี
JimmyJames

ตัวอย่างล่าสุดที่ฉันพบคือ elm เมื่อเทียบกับ C, C ++, C #, Java, ECMAScript และอื่น ๆ ฉันได้อัปเดตคำถามของฉัน @JimmyJames
atoth

2
นี่เป็นครั้งแรกที่ฉันได้ยิน ปฏิกิริยาแรกของฉันคือการเรียก BS สังเกตคำพังพอน: ในทางปฏิบัติ
JimmyJames

@atoth ฉันจะแก้ไขชื่อคำถามของคุณเพื่อให้ชัดเจนขึ้นเนื่องจากมีคำถามที่ไม่เกี่ยวข้องจำนวนมากซึ่งมีลักษณะคล้ายกับมัน (เช่น "RuntimeException" vs "Exception" ใน Java) หากคุณไม่ชอบชื่อใหม่คุณสามารถแก้ไขได้อีกครั้ง
Andres F.

ตกลงฉันต้องการให้มันเป็นแบบทั่วไปมากพอ แต่ฉันสามารถเห็นด้วยกับสิ่งที่ช่วยได้ขอบคุณสำหรับการบริจาคของคุณ @AndresF.!
atoth

คำตอบ:


28

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

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

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

ลองพิจารณาตัวอย่างต่อไปนี้ คุณสามารถวางสิ่งนี้ลงในhttp://elm-lang.org/tryหากคุณต้องการดูมันในทางปฏิบัติ

import Html exposing (Html, Attribute, beginnerProgram, text, div, input)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import String

main =
  beginnerProgram { model = "", view = view, update = update }

-- UPDATE

type Msg = NewContent String

update (NewContent content) oldContent =
  content

getDefault = Result.withDefault "Please enter an integer" 

double = Result.map (\x -> x*2)

calculate = String.toInt >> double >> Result.map toString >> getDefault

-- VIEW

view content =
  div []
    [ input [ placeholder "Number to double", onInput NewContent, myStyle ] []
    , div [ myStyle ] [ text (calculate content) ]
    ]

myStyle =
  style
    [ ("width", "100%")
    , ("height", "40px")
    , ("padding", "10px 0")
    , ("font-size", "2em")
    , ("text-align", "center")
    ]

หมายเหตุString.toIntในcalculateฟังก์ชั่นมีความเป็นไปได้ของความล้มเหลว ใน Java สิ่งนี้มีความเป็นไปได้ที่จะโยนข้อยกเว้นรันไทม์ เนื่องจากมีการอ่านอินพุตของผู้ใช้จึงมีโอกาสที่ดีพอสมควร Elm บังคับให้ฉันจัดการกับมันด้วยการคืน a Resultแต่ให้สังเกตว่าฉันไม่ต้องจัดการกับมันทันที ฉันสามารถเพิ่มอินพุตเป็นสองเท่าและแปลงเป็นสตริงได้จากนั้นตรวจสอบอินพุตที่ไม่ดีในgetDefaultฟังก์ชัน สถานที่นี้เหมาะสำหรับการตรวจสอบมากกว่าจุดที่เกิดข้อผิดพลาดหรือสูงกว่าใน call stack

วิธีที่คอมไพเลอร์บังคับมือของเรานั้นมีความละเอียดยิ่งกว่าข้อยกเว้นที่ตรวจสอบโดยจาวา คุณจำเป็นต้องใช้ฟังก์ชั่นที่เฉพาะเจาะจงอย่างเช่นResult.withDefaultเพื่อดึงค่าที่คุณต้องการ ในขณะที่ในทางเทคนิคคุณสามารถใช้กลไกแบบนั้นในทางที่ผิด แต่ก็มีประเด็นไม่มากนัก เนื่องจากคุณสามารถเลื่อนการตัดสินใจได้จนกว่าคุณจะทราบว่ามีข้อความแจ้งข้อผิดพลาดเริ่มต้น / ข้อผิดพลาดที่ดี


8
That means you get a compiler error if you don't handle the error.- นั่นคือเหตุผลเบื้องหลังการตรวจสอบข้อยกเว้นใน Java แต่เราทุกคนรู้ดีว่าทำงานได้ดีเพียงใด
Robert Harvey

4
@RobertHarvey ในทางใดก็ตามข้อยกเว้นการตรวจสอบของ Java เป็นรุ่นที่คนยากจนของนี้ น่าเสียดายที่พวกเขาสามารถ "กลืน" (เหมือนในตัวอย่างของ OP) พวกมันไม่ใช่ประเภทจริงทำให้พวกมันเป็นเส้นทางเพิ่มเติมที่ไม่เกี่ยวข้องกับการไหลของรหัส ภาษาที่มีระบบการพิมพ์ที่ดีขึ้นช่วยให้คุณสามารถเข้ารหัสข้อผิดพลาดเป็นค่าชั้นแรกซึ่งเป็นสิ่งที่คุณทำใน (พูด) Haskell กับMaybe, Eitherฯลฯ ลักษณะ Elm เช่นนั้นก็นำหน้าจากภาษาเช่น ML, OCaml หรือ Haskell
Andres F.

3
@JimmyJames ไม่พวกเขาไม่ได้บังคับคุณ คุณจะต้อง "จัดการ" ข้อผิดพลาดเมื่อคุณต้องการใช้ค่า ถ้าฉันทำx = some_func()ฉันไม่ต้องทำอะไรนอกจากฉันต้องการตรวจสอบคุณค่าของxซึ่งในกรณีนี้ฉันสามารถตรวจสอบว่าฉันมีข้อผิดพลาดหรือค่า "ถูกต้อง"; ยิ่งไปกว่านั้นมันเป็นข้อผิดพลาดประเภทคงที่ที่จะพยายามใช้งานแทนกันดังนั้นฉันจึงไม่สามารถทำได้ ถ้าประเภทของ Elm ทำงานอะไรเช่นภาษาทำงานอื่น ๆ ฉันสามารถทำสิ่งต่าง ๆ เช่นเขียนค่าจากฟังก์ชั่นต่าง ๆก่อนที่ฉันจะรู้ว่าพวกเขามีข้อผิดพลาดหรือไม่! นี่เป็นเรื่องปกติของภาษา FP
Andres F.

6
@atoth แต่คุณจะมีกำไรที่สำคัญและมีความเป็นเหตุผลที่ดีมาก (ตามที่ได้รับการอธิบายในคำตอบหลายคำถามของคุณ) ฉันขอแนะนำให้คุณเรียนรู้ภาษาที่มีไวยากรณ์คล้าย ML และคุณจะเห็นว่าการปลดเปลื้องมันเป็นอย่างไรเพื่อกำจัดไวยากรณ์ C-like cruft (ML โดยวิธีการได้รับการพัฒนาในต้นปี 70 ซึ่งทำให้มันคร่าว ๆ ร่วมสมัยของ C) ผู้ที่ออกแบบระบบประเภทนี้จะพิจารณารูปแบบของไวยากรณ์นี้ซึ่งแตกต่างจาก C :) ในขณะที่คุณอยู่ที่นี่มันจะไม่เจ็บที่จะเรียนรู้ Lisp เช่นกัน :)
Andres F.

6
@atoth หากคุณต้องการที่จะใช้สิ่งหนึ่งจากทั้งหมดนี้ใช้เวลาหนึ่งนี้: เสมอให้แน่ใจว่าคุณไม่ตกเหยื่อเพื่อร้องไห้สะอึกสะอื้น Paradox อย่าหงุดหงิดกับไวยากรณ์ใหม่ อาจเป็นเพราะคุณสมบัติที่ทรงพลังที่คุณไม่คุ้นเคยกับ :)
Andres F.

10

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

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

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

ความแตกต่างระหว่างระบบประเภทที่แตกต่างกันนั้นโดยพื้นฐานแล้วมีจำนวนเท่าใดและพฤติกรรมการใช้งานแบบรันไทม์ที่ซับซ้อนซึ่งพวกเขาสามารถพิสูจน์ได้ว่าไม่เกิด ระบบประเภทที่อ่อนแอเช่น Java สามารถพิสูจน์สิ่งพื้นฐานได้เท่านั้น ยกตัวอย่างเช่น Java สามารถพิสูจน์ได้ว่าวิธีการที่จะพิมพ์เป็นกลับมาที่ไม่สามารถกลับมาเป็นString Listแต่ตัวอย่างเช่นมันไม่สามารถพิสูจน์ได้ว่าวิธีการจะไม่กลับมา มันไม่สามารถพิสูจน์ได้ว่าวิธีการนี้จะไม่เกิดข้อยกเว้น และไม่สามารถพิสูจน์ได้ว่าจะไม่ส่งคืนความผิด String  - ผู้ใดก็ตามStringจะพึงพอใจตัวตรวจสอบประเภท (และแน่นอนแม้nullจะตอบสนองเป็นอย่างดี.) มีแม้กระทั่งสิ่งที่ง่ายมากที่ Java ไม่สามารถพิสูจน์ได้มีซึ่งเป็นเหตุผลที่เรามีข้อยกเว้นเช่นArrayStoreException, หรือทุกคนที่ชื่นชอบClassCastExceptionNullPointerException

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

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

ดังนั้นพวกเขาไม่ได้พูดว่า "เราไม่ได้ใช้การยกเว้น" พวกเขากำลังพูดว่า "สิ่งต่าง ๆ ที่อาจเป็นข้อยกเว้นแบบรันไทม์ในภาษาทั่วไปที่โปรแกรมเมอร์ทั่วไปที่มาถึง Elm จะมีประสบการณ์ด้วยถูกติดตั้งโดยระบบประเภท" แน่นอนว่าคนที่มาจาก Idris, Agda, Guru, Epigram, Isabelle / HOL, Coq หรือภาษาที่คล้ายกันจะเห็น Elm ค่อนข้างอ่อนแอเมื่อเปรียบเทียบ คำสั่งนี้มีวัตถุประสงค์เพิ่มเติมที่ Java, C typical, C ++, Objective-C, PHP, ECMAScript, Python, Ruby, Perl, ... โปรแกรมเมอร์


5
หมายเหตุถึงบรรณาธิการที่มีศักยภาพ: ฉันเสียใจมากเกี่ยวกับการใช้ฟิล์มเนกาทีฟสองเท่าและสามเท่า อย่างไรก็ตามฉันทิ้งไว้ในจุดประสงค์: ระบบประเภทรับประกันว่าไม่มีพฤติกรรมรันไทม์บางประเภทเช่นพวกเขารับประกันสิ่งที่ไม่เกิดขึ้น และฉันต้องการให้สูตรนั้น "พิสูจน์ว่าไม่เกิดขึ้น" ไม่เป็นอันตรายซึ่งน่าเสียดายที่นำไปสู่สิ่งปลูกสร้างเช่น "มันไม่สามารถพิสูจน์ได้ว่าวิธีการหนึ่งจะไม่กลับมา" หากคุณสามารถหาวิธีปรับปรุงสิ่งเหล่านี้ได้โปรดดำเนินการต่อไป แต่โปรดจำไว้ข้างต้น ขอขอบคุณ!
Jörg W Mittag

2
คำตอบที่ดีโดยรวม แต่ nitpick ขนาดเล็กหนึ่งตัว: "ตัวตรวจสอบชนิดคล้ายกับตัวพิสูจน์ทฤษฎีบท" ที่จริงแล้วตัวตรวจสอบชนิดนั้นคล้ายกับตัวตรวจสอบทฤษฎีมากกว่าพวกเขาทั้งสองทำการตรวจสอบไม่ใช่หัก
gardenhead

4

Elm สามารถรับประกันได้ว่าไม่มีข้อยกเว้นสำหรับรันไทม์ด้วยเหตุผลเดียวกัน C สามารถรับประกันได้ว่าไม่มีข้อยกเว้นของรันไทม์: ภาษาไม่รองรับแนวคิดของข้อยกเว้น

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

นี่คือตัวอย่างจากการแนะนำ (ง่ายเล็กน้อย):

view : String -> String 
view userInputAge =
  case String.toInt userInputAge of
    Err msg ->
        text "Not a valid number!"

    Ok age ->
        text "OK!"

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

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


2
@atoth นี่คือตัวอย่าง ลองนึกภาพภาษา A ช่วยให้มีข้อยกเว้น doSomeStuff(x: Int): Intแล้วคุณจะได้รับฟังก์ชั่น โดยปกติคุณคาดหวังว่ามันจะคืนค่าIntแต่มันสามารถทำให้เกิดข้อยกเว้นได้หรือไม่? หากไม่ดูซอร์สโค้ดคุณจะไม่รู้ ในทางตรงกันข้ามภาษา B ที่เข้ารหัสข้อผิดพลาดผ่านประเภทอาจมีฟังก์ชั่นเดียวกันประกาศเช่นนี้: doSomeStuff(x: Int): ErrorOrResultOfType<Int>(ใน Elm ประเภทนี้มีชื่อจริงResult) ซึ่งแตกต่างจากในกรณีแรกตอนนี้มันชัดเจนทันทีว่าฟังก์ชันอาจล้มเหลวและคุณต้องจัดการอย่างชัดเจน
Andres F.

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

2
@JimmyJames ไม่เหมือนกับการตรวจสอบข้อยกเว้นเพราะข้อยกเว้นไม่ได้เขียนสามารถถูกละเว้น ("การกลืน") และไม่ใช่ค่าระดับเฟิร์สคลาส :) ฉันแนะนำให้เรียนภาษาที่ฟังก์ชั่นแบบคงที่เพื่อให้เข้าใจอย่างแท้จริง นี่ไม่ใช่สิ่งใหม่ที่ Elm สร้างขึ้น - นี่คือวิธีที่คุณเขียนโปรแกรมในภาษาเช่น ML หรือ Haskell และแตกต่างจาก Java
Andres F.

2
@AndresF this is how you program in languages such as ML or Haskellใน Haskell ใช่ ML, ไม่ โรเบิร์ตฮาร์เปอร์ผู้บริจาครายใหญ่มาตรฐาน ML และนักวิจัยภาษาโปรแกรมจะพิจารณาข้อยกเว้นที่จะเป็นประโยชน์ ประเภทข้อผิดพลาดอาจเข้ามาในองค์ประกอบของฟังก์ชันในกรณีที่คุณสามารถรับประกันว่าจะไม่มีข้อผิดพลาดเกิดขึ้น ข้อยกเว้นยังมีประสิทธิภาพที่แตกต่างกัน คุณไม่ต้องจ่ายเงินสำหรับการยกเว้นที่ไม่ได้ถูกโยน แต่คุณจ่ายสำหรับการตรวจสอบค่าความผิดพลาดทุกครั้งและการยกเว้นเป็นวิธีที่เป็นธรรมชาติในการแสดงการย้อนรอยในอัลกอริทึมบางอย่าง
Doval

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

2

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

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

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

โปรดทราบว่าเมื่อคุณไม่ใช้ข้อยกเว้นข้อผิดพลาดจะถูกเข้ารหัสในรูปแบบอื่นและน่าแปลกใจน้อยกว่า จากเอกสารของ Elm :

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

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


ฉันกำลังอ่านผิดหรือว่าพวกเขาแค่เล่นเกมความหมายหรือไม่ พวกมันออกกฎหมายชื่อ "run time exception" แต่จากนั้นแทนที่ด้วยกลไกที่แตกต่างกันที่สื่อถึงข้อผิดพลาดในสแต็ก ดูเหมือนว่าเพียงแค่เปลี่ยนการใช้งานข้อยกเว้นเป็นแนวคิดหรือวัตถุที่คล้ายกันซึ่งทำให้ข้อความแสดงข้อผิดพลาดแตกต่างกัน นั่นแทบจะไม่ทำให้โลกสั่นสะเทือน มันก็เหมือนกับภาษาที่พิมพ์แบบคงที่ใด ๆ เปรียบเทียบการสลับจาก COM HRESULT ไปเป็นข้อยกเว้น. NET กลไกที่แตกต่างกัน แต่ยังคงเป็นข้อยกเว้นเวลาทำงานไม่ว่าคุณจะเรียกมันว่าอะไร
Mike รองรับ Monica

@ ไมค์พูดตามตรงฉันไม่ได้ดูรายละเอียดเอล์ม ตัดสินโดยเอกสารพวกเขามีประเภทResultและTaskที่คล้ายกับที่คุ้นเคยEitherและFutureมาจากภาษาอื่น ๆ ซึ่งแตกต่างจากข้อยกเว้นค่าของประเภทเหล่านี้สามารถรวมกันและในบางจุดคุณต้องจัดการพวกเขาอย่างชัดเจน: พวกเขาเป็นตัวแทนของมูลค่าที่ถูกต้องหรือข้อผิดพลาด? ฉันไม่ได้อ่านใจ แต่การขาดความประหลาดใจนี้โปรแกรมเมอร์น่าจะเป็นสิ่งที่นักออกแบบของ Elm มีความหมายโดย "ไม่มีข้อยกเว้นเวลาทำงาน" :)
Andres F.

@ ไมค์ฉันยอมรับว่ามันไม่ได้ทำให้แผ่นดินไหว ความแตกต่างกับข้อยกเว้น runtime คือพวกเขาไม่ชัดเจนในประเภท (เช่นคุณไม่สามารถรู้ได้โดยไม่ต้องดูที่ซอร์สโค้ดไม่ว่าจะเป็นส่วนหนึ่งของรหัสอาจโยน); ข้อผิดพลาดในการเข้ารหัสในประเภทนั้นชัดเจนมากและป้องกันไม่ให้โปรแกรมเมอร์มองเห็นสิ่งเหล่านี้นำไปสู่รหัสที่ปลอดภัยยิ่งขึ้น สิ่งนี้ทำโดยใช้หลายภาษา FP และแน่นอนไม่มีอะไรใหม่
Andres F.

1
ตามความคิดเห็นของคุณฉันคิดว่ามี"การตรวจสอบประเภทคงที่"มากกว่านั้น คุณสามารถเพิ่มลงใน JS โดยใช้ Typescript ซึ่งมีข้อ จำกัด น้อยกว่าระบบนิเวศแบบ "สร้างหรือทำลาย" ใหม่
atoth

1
@AndresF .: เทคนิคการพูดคุณลักษณะใหม่ล่าสุดของระบบชนิดของ Java คือ Parametric Polymorphism ซึ่งเกิดขึ้นในช่วงปลายยุค 60 ดังนั้นในการพูดคำว่า "ทันสมัย" เมื่อคุณหมายถึง "ไม่ Java" ค่อนข้างถูกต้อง
Jörg W Mittag

0

Elm อ้างว่า:

ไม่มีข้อผิดพลาดรันไทม์ในทางปฏิบัติ ไม่มีค่าว่าง ไม่มีการกำหนดไม่ได้เป็นฟังก์ชั่น

แต่คุณถามเกี่ยวกับรันไทม์ข้อยกเว้น มีความแตกต่าง

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

ดังนั้นคำถามควรเป็น:

ประโยชน์ของการมี "ไม่มีข้อผิดพลาด runtime" คืออะไร?

หากคุณสามารถเขียนโค้ดที่ไม่มีข้อผิดพลาดรันไทม์โปรแกรมของคุณจะไม่ผิดพลาด

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