Elm'in iddia ettiği gibi “çalışma zamanı istisnası yok” unun avantajı nedir?


17

Bazı diller "diğer çalışma zamanı istisnaları" bulunmadığını ve bu dillere sahip diğer diller için açık bir avantaj olduğunu iddia etmektedir.

Bu konuda kafam karıştı.

Çalışma zamanı istisnası bildiğim kadarıyla ve iyi kullanıldığında sadece bir araçtır:

  • "kirli" durumları iletebilirsiniz (beklenmedik verilere atarak)
  • yığın ekleyerek hata zincirine işaret edebilirsiniz
  • karmaşa (ör. geçersiz girişte boş bir değer döndürme) ve geliştiricinin dikkatini gerektiren güvenli olmayan kullanım (örneğin geçersiz girdide istisna atma) arasında ayrım yapabilirsiniz
  • hata ayıklama çabalarına yardımcı olacak daha fazla yararlı ayrıntı sağlayan özel durum mesajı ile hatanıza ayrıntı ekleyebilirsiniz (teorik olarak)

Diğer yandan, istisnaları "yutan" bir yazılımda hata ayıklamak gerçekten zor. Örneğin

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

Yani soru şu: "çalışma zamanı istisnası yok" un güçlü ve teorik avantajı nedir?


Misal

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

Uygulamada çalışma zamanı hatası yok. Boş değil. Tanımlanmamış hiçbir işlev değildir.


Bahsettiğiniz dillerin bir ya da iki örneğini ve / veya bu tür iddialara bağlantı vermenin faydalı olacağını düşünüyorum. Bu, çeşitli şekillerde yorumlanabilir.
JimmyJames

Bulduğum en son örnek C, C ++, C #, Java, ECMAScript, vb ile karşılaştırıldığında karaağaç oldu. Ben sorum @JimmyJames
atoth

2
Bunu ilk duydum. İlk tepkim BS'yi aramak.
Gelincik

@atoth Daha net olması için soru başlığınızı düzenleyeceğim, çünkü buna benzeyen birden fazla ilgisiz soru var (Java'da "RuntimeException" ve "Exception" gibi). Yeni başlığı beğenmediyseniz, tekrar düzenlemekten çekinmeyin.
Andres F.

Tamam, yeterince genel olmasını istedim, ama eğer yardımcı olursa, @AndresF katkınız için teşekkürler.!
atoth

Yanıtlar:


28

İstisnalar çok sınırlayıcı anlambilime sahiptir. Tam olarak atıldıkları yere veya doğrudan çağrı yığınına yukarı doğru işlenmelidirler ve derleme zamanında programcıya herhangi bir gösterge yoktur.

Bunu, hataların her ikisi de değer olan Sonuçlar veya Maybes olarak kodlandığı Elm ile karşılaştırın . Bu, hatayı işlemezseniz bir derleyici hatası aldığınız anlamına gelir. Kullanımlarını uygun bir zamana ertelemek için bunları bir değişkente veya hatta bir koleksiyonda saklayabilirsiniz. Hataları, her yerde çok benzer try-catch bloklarını tekrarlamak yerine uygulamaya özgü bir şekilde işlemek için bir işlev oluşturabilirsiniz. Onları sadece tüm parçaları başarılı olduğunda başarılı olan bir hesaplamaya zincirleyebilirsiniz ve bunların tek bir deneme bloğuna sıkıştırılması gerekmez. Yerleşik sözdizimi ile sınırlı değilsiniz.

Bu "istisnaları yutma" gibi bir şey değildir. Tür sisteminde hata koşullarını açıkça ortaya koyuyor ve bunları ele almak için çok daha esnek alternatif anlambilim sağlıyor.

Aşağıdaki örneği ele alalım. Eğer eylemde görmek istiyorsanız bunu http://elm-lang.org/try içine yapıştırabilirsiniz .

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")
    ]

Not String.toIntiçinde calculateişlevin başarısız imkanına sahiptir. Java'da bunun bir çalışma zamanı istisnası atma potansiyeli vardır. Kullanıcı girdisini okurken, oldukça iyi bir şansı vardır. Elm bunun yerine beni geri dönerek onunla başa çıkmaya zorluyor Result, ama hemen onunla uğraşmak zorunda olmadığımı fark et. Girişi iki katına çıkarabilir ve bir dizeye dönüştürebilirim, sonragetDefault işlevde kötü giriş olup olmadığını kontrol edebilirim . Burası, kontrol için hatanın oluştuğu noktadan veya çağrı yığınında yukarı doğru çok daha uygundur.

Derleyicinin elimizi zorlama şekli de Java'nın denetlenen istisnalarından çok daha incedir. İstediğiniz Result.withDefaultdeğeri ayıklamak gibi çok özel bir işlev kullanmanız gerekir . Teknik olarak bu tür bir mekanizmayı kötüye kullanabilmenize rağmen, pek bir anlamı yoktur. Yapacağınız iyi bir varsayılan / hata mesajını öğreninceye kadar kararı erteleyebileceğiniz için, kullanmamanız için hiçbir neden yoktur.


8
That means you get a compiler error if you don't handle the error.- Eh, Java'daki Checked Exceptions'ın arkasındaki sebep buydu, ama hepimiz bunun ne kadar iyi çalıştığını biliyoruz.
Robert Harvey

4
@RobertHarvey Bir bakıma, Java'nın kontrol ettiği istisnalar, bunun kötü adam versiyonuydu. Ne yazık ki "yutulabilirler" (OP örneğinde olduğu gibi). Bunlar aynı zamanda gerçek türler değildi, bu da onları kod akışına ek bir yol yaptı. Daha iyi tip sistemlerle Diller sen (söz hakkından) yapması gereken şeydir birinci sınıf değerlerine olarak kodlamak hataları ile Haskell için izin Maybe, Eitherbunun gibi vb Elm görünüyor böyle ML, OCaml veya Haskell olarak dilden bir sayfayı alıyor.
Andres F.

3
@JimmyJames Hayır, sizi zorlamıyorlar. Hatayı yalnızca değeri kullanmak istediğinizde "işlemeniz" gerekir. Ben yaparsam x = some_func(), ben yok olması ben değerini incelemek istemedikçe bir şey yapmak xbir hata ya da bir "geçerli" bir değere sahip olmadığını kontrol edebilirim bu durumda; dahası, birini diğerinin yerine kullanmaya çalışmak statik bir hatadır, bu yüzden yapamam. Elm tipleri diğer işlevsel dillerde böyle bir şey çalışıyorsanız, aslında farklı fonksiyonlardan gelen oluşturma değerler gibi şeyler yapabilir önce bile onlar ya da değil hata olup olmadıklarını biliyorum! Bu FP dillerinde tipiktir.
Andres F.

6
@atoth Ama do önemli kazanımlar var ve orada olan çok iyi bir nedeni (olduğu gibi sorunuzun birden cevapları açıklanmıştır). ML benzeri bir sözdizimi ile bir dil öğrenmenizi gerçekten teşvik ediyorum ve C benzeri sözdizimi hammaddesinden kurtulmanın ne kadar özgürleştirici olduğunu göreceksiniz (ML, bu arada, 70'lerin başında geliştirildi, bu da kabaca çağdaş bir C). Bu tür yazım sistemlerini tasarlayan insanlar, C'nin aksine bu tür bir sözdizimini normal kabul ederler :) Siz de Lisp'i öğrenmek incitmez :)
Andres F.

6
@atoth Tüm bunlardan bir şey almak istiyorsanız, bunu alın: Daima Blub Paradoksuna avlanmadığınızdan emin olun . Yeni sözdiziminde rahatsız olmayın. Belki bilmediğiniz güçlü özellikler nedeniyle oradadır :)
Andres F.

10

Bu ifadeyi anlamak için öncelikle statik tip bir sistemin bize ne satın aldığını anlamalıyız. Esasen, statik tip bir sistemin bize verdiği şey bir garantidir: program tipi kontrol edilirse , belirli bir çalışma zamanı davranışı sınıfı meydana gelemez.

Kulağa iğrenç geliyor. Tip denetleyicisi teorem denetleyicisine benzer. (Aslında, Curry-Howard-İzomorfizme göre onlar aynı şeydir.) Teoremler hakkında çok tuhaf olan bir şey, bir teoremi kanıtladığınızda, teoremin ne söylediğini, artık daha fazla kanıtlamadığınızdır. (Örneğin, neden biri "Bu programı doğruladım kanıtladı" derse, her zaman "lütfen 'doğru' tanımlayın" diye sormalısınız.) Aynı şey tip sistemler için de geçerlidir. Biz dediğimizde ise ne anlama geldiğini, "Bir program tipi-güvenlidir" değil hiçbir olası hata oluşabilir. Sadece tip sisteminin bize önlemeyi vaat ettiği hataların meydana gelemeyeceğini söyleyebiliriz.

Böylece, programların sonsuz sayıda farklı çalışma zamanı davranışı olabilir. Bunlardan, sonsuz sayıda yararlıdır, ancak sonsuz sayıda birçok "yanlıştır" (çeşitli "doğruluk" tanımları için). Statik tip bir sistem, sonsuz sayıda yanlış çalışma zamanı davranışının belirli bir sonlu, sabit setinin meydana gelemeyeceğini kanıtlamamıza izin verir.

Farklı tip sistemler arasındaki fark, temel olarak hangi, kaç tane ve ne kadar karmaşık çalışma zamanı davranışlarının gerçekleşmediğini kanıtlayabilmesidir. Java gibi zayıf tip sistemler yalnızca çok temel şeyleri kanıtlayabilir. Örneğin, Java, döndüren olarak yazılan bir yöntemin a Stringdöndüremeyeceğini kanıtlayabilir List. Ama, örneğin, bu olabilir değil yöntem döndürmez olmayacağını kanıtlıyor. Yöntemin bir istisna atmayacağını da kanıtlayamaz. Ve yanlış döndürmeyeceğini kanıtlayamaz String - herhangi Stringbiri tip denetleyicisini tatmin edecektir. (Ve tabii ki, hatta nullaynı zamanda onu tatmin edecektir.) Java ispat edemez bile çok basit şeyler vardır, biz gibi istisnalar neden olan ArrayStoreException, ClassCastExceptionya da herkesin en sevdiği, NullPointerException.

Agda gibi daha güçlü yazım sistemleri de "iki argümanın toplamını döndürür" veya "argüman olarak aktarılan listenin sıralı halini döndürür" gibi şeyleri kanıtlayabilir.

Şimdi, Elm tasarımcılarının çalışma zamanı istisnaları olmadığı ifadesiyle ne anlama geldiği, Elm'in tip sisteminin, diğer dillerde gerçekleşmediği kanıtlanamayan ve dolayısıyla yol gösterebileceği çalışma zamanı davranışlarının (önemli bir kısmı) olmadığını kanıtlayabileceğidir. çalışma zamanında hatalı davranışa (en iyi durumda bir istisna anlamına gelir, en kötü durumda bir çarpışma anlamına gelir ve en kötü durumda çarpışma, istisna ve sadece sessizce yanlış bir sonuç anlamına gelir).

Yani, onlar vardır değil "biz istisnalar uygulamak değil" diyerek. "Elm'e gelen tipik programcıların deneyimleyeceği tipik dillerde çalışma zamanı istisnaları olacak şeyler, tür sistemi tarafından yakalanıyor" diyorlar. Tabii ki, Idris, Agda, Guru, Epigram, Isabelle / HOL, Coq veya benzer dillerden gelen biri, Elm'i karşılaştırıldığında oldukça zayıf görecektir. İfade daha çok tipik Java, C♯, C ++, Objective-C, PHP, ECMAScript, Python, Ruby, Perl,… programcılarına yöneliktir.


5
Potansiyel editörlere not: Çift ve hatta üçlü negatiflerin kullanımı için çok üzgünüm. Ancak, onları bilerek bıraktım: tip sistemler belirli çalışma zamanı davranışlarının yokluğunu garanti eder, yani belirli şeylerin gerçekleşmemesini garanti ederler. Ve bu formülasyonu "gerçekleşmediğini kanıtlamak" için sağlam tutmak istedim, bu ne yazık ki "bir yöntemin geri dönmeyeceğini kanıtlayamıyor" gibi yapılara yol açıyor. Bunları iyileştirmenin bir yolunu bulabilirseniz, lütfen yukarıdakileri aklınızda bulundurun. Teşekkür ederim!
Jörg W Mittag

2
Genel olarak iyi cevap, ancak küçük bir nitpick: "bir tür denetleyici bir teorem kanıtlayıcısına benzer." Aslında, bir tür denetleyicisi bir teorem denetleyicisine daha yakındır: her ikisi de kesinti değil, doğrulama yapar .
gardenhead

4

Elm aynı nedenden dolayı çalışma zamanı istisnasını garanti edemez C aynı zamanda çalışma zamanı istisnasını garanti edemez: Dil istisnalar kavramını desteklemez.

Elm'in çalışma zamanında hata durumlarını bildirmenin bir yolu vardır, ancak bu sistem istisna değildir, "Sonuçlar" dır. Başarısız olabilecek bir işlev, normal bir değer veya hata içeren bir "Sonuç" döndürür. Elms güçlü bir şekilde yazılmıştır, bu nedenle bu tür sistemde açıktır. Bir işlev her zaman bir tamsayı döndürürse, türüne sahiptir Int. Ancak, bir tamsayı döndürürse veya başarısız olursa, dönüş türü olur Result Error Int. (Dize hata iletisidir.) Bu, sizi çağrı sitesinde her iki durumu da açıkça işlemeye zorlar.

Girişten bir örnek (biraz basitleştirilmiş):

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

    Ok age ->
        text "OK!"

toIntGiriş ayrıştırılamazsa işlev başarısız olabilir, bu nedenle dönüş türü olur Result String int. Gerçek tamsayı değerini elde etmek için, desen eşleştirme yoluyla "paketini açmanız" gerekir; bu da sizi her iki durumu da ele almaya zorlar.

Sonuçlar ve istisnalar temelde aynı şeyi yapar, önemli fark "temerrütler" dir. İstisnalar programı varsayılan olarak patlatacak ve sonlandıracaktır ve bunları işlemek istiyorsanız bunları açıkça yakalamanız gerekir. Sonuç başka bir yol - varsayılan olarak bunları işlemek zorundasınız, bu yüzden programı sonlandırmalarını istiyorsanız, bunları en üste kadar açık bir şekilde geçirmeniz gerekir. Bu davranışın nasıl daha sağlam koda yol açabileceğini görmek kolaydır.


2
@atoth İşte bir örnek. A dilinin istisnalara izin verdiğini hayal edin. Sonra size fonksiyon verilir doSomeStuff(x: Int): Int. Normalde bir geri dönmesini beklersiniz Int, ancak bir istisna da atabilir mi? Kaynak koduna bakmadan bilemezsiniz. Aksine, hataları türler aracılığıyla kodlayan bir dil B aşağıdaki gibi aynı işleve sahip olabilir: doSomeStuff(x: Int): ErrorOrResultOfType<Int>(Elm'de bu tür aslında adlandırılır Result). İlk durumdan farklı olarak, şimdi işlevin başarısız olup olmayacağı hemen belli oluyor ve bunu açıkça ele almanız gerekiyor.
Andres F.

1
@RobertHarvey'in başka bir cevaba yaptığı yorumda ima ettiği gibi, bu temelde Java'daki kontrol edilen istisnalar gibi görünüyor. En istisnaların kontrol edildiği ilk günlerde Java ile çalışmayı öğrendiğim şey, meydana geldikleri noktada her zaman hatalara kod yazmak zorunda kalmamanızdır.
JimmyJames

2
@JimmyJames İstisnalar oluşturmadığı, göz ardı edilebildiği ("yutulabilen") ve birinci sınıf değerler olmadığı için kontrol edilen istisnalar gibi değil :) Bunu gerçekten anlamak için statik olarak yazılmış işlevsel bir dil öğrenmenizi öneririm. Bu Elm oluşan yeni model şey değil - bu nasıl böyle ML veya Haskell olarak dilde programlamak ve Java farklı.
Andres F.

2
@AndresF. this is how you program in languages such as ML or HaskellHaskell'de evet; ML, hayır. Standart ML'ye ve programlama dili araştırmacısına önemli bir katkıda bulunan Robert Harper, istisnaların yararlı olduğunu düşünmektedir . Bir hata oluşmayacağını garanti edebileceğiniz durumlarda hata türleri fonksiyon kompozisyonuna girebilir. İstisnalar da farklı performansa sahiptir. Atılmayan istisnalar için ödeme yapmazsınız, ancak her seferinde hata değerlerini kontrol etmek için ödeme yaparsınız ve istisnalar bazı algoritmalarda geri izlemeyi ifade etmenin doğal bir yoludur
Doval

2
@JimmyJames Umarım kontrol edilen istisnaların ve gerçek hata türlerinin sadece yüzeysel olarak benzer olduğunu görüyorsunuz. İşaretli istisnalar zarif bir şekilde birleşmez, kullanımı zahmetlidir ve ifade odaklı değildir (ve bu nedenle, Java'da olduğu gibi bunları "yutabilirsiniz"). Kontrol edilmeyen istisnalar daha az hantaldır, bu yüzden her yerde ancak Java'da normdurlar, ancak sizi gezme olasılığı daha yüksektir ve bir işlev bildirimine bakarak atar veya atmaz, programınızı zorlaştırırsınız. anlamak.
Andres F.

2

İlk olarak, "yutma" istisna örneğinizin genel olarak korkunç bir uygulama olduğunu ve çalışma süresi istisnası olmadan tamamen ilgisiz olduğunu lütfen unutmayın; Bunu düşündüğünüzde, bir çalışma zamanı hatası yaptınız, ancak gizlemeyi ve bu konuda hiçbir şey yapmamayı seçtiniz. Bu genellikle anlaşılması zor hatalara yol açar.

Bu soru herhangi bir şekilde yorumlanabilir, ancak yorumlarda Elm'den bahsettiğinizden, bağlam daha açıktır.

Karaağaç, diğer şeylerin yanı sıra, statik olarak yazılmış bir programlama dilidir. Bu tür tip sistemlerin avantajlarından biri, program kullanılmadan önce birçok hata sınıfının (hepsi olmasa da) derleyici tarafından yakalanmasıdır. Bazı hata türleri , istisna olarak atılmak yerine, türlerde (Elm Resultve gibi) kodlanabilir Task. Elm tasarımcıları bu anlama gelir: birçok hata "çalışma zamanı" yerine derleme zamanında yakalanır ve derleyici sizi görmezden gelmek ve en iyisini ummak yerine onlarla başa çıkmaya zorlar. Bunun neden bir avantaj olduğu açıktır: programcı kullanıcı yapmadan önce bir sorunun farkına varırsa.

İstisnalar kullanmadığınızda, hataların diğer daha az şaşırtıcı yollarla kodlandığını unutmayın. Gönderen Elm belgelerine :

Elm'in garantilerinden biri, çalışma zamanı hatalarını pratikte görmeyeceğinizdir. NoRedInk Elm'i yaklaşık bir yıldır üretimde kullanıyor ve hala bir tane yok! Elm'deki tüm garantiler gibi bu da temel dil tasarım seçeneklerine inmektedir. Bu durumda, Elm'in hataları veri olarak ele alması bize yardımcı olur. (Burada çok fazla veri yaptığımızı fark ettiniz mi?)

Karaağaç tasarımcıları "çalışma zamanı istisnası yok" iddiasında bulunmak konusunda biraz cesurlar , ancak "pratikte" nitelendiriyorlar. Muhtemelen ne anlama geldiğini "JavaScript kodlama daha az beklenmedik hatalar" dir.


Yanlış mı okuyorum, yoksa sadece semantik bir oyun mu oynuyorlar? "Çalışma zamanı istisnası" adını yasadışı olarak kabul ederler, ancak yerine, yığının üstüne hata bilgilerini ileten farklı bir mekanizma ile değiştirirler. Bu, bir istisnanın uygulanmasını, hata mesajını farklı şekilde uygulayan benzer bir kavram veya nesneye dönüştürmek gibi görünür. Bu neredeyse dünyayı sarsıyor. Statik olarak yazılmış herhangi bir dile benzer. COM HRESULT'dan .NET istisnasına geçişi karşılaştırın. Farklı mekanizma, ama yine de ne derseniz deyin, çalışma zamanı istisnasıdır.
Mike Monica'nın

@Mike Dürüst olmak gerekirse Elm'e ayrıntılı olarak bakmadım. Docs bakılırsa, onlar türleri vardır Resultve Taskhangi daha tanıdık çok benzer Eitherve Futurediğer dillerden. İstisnalardan farklı olarak, bu türlerin değerleri birleştirilebilir ve bir noktada bunları açıkça ele almalısınız: geçerli değeri mi yoksa hatayı mı temsil ediyorlar? Zihin okumam, ama programcıyı şaşırtmanın bu eksikliği muhtemelen Elm tasarımcılarının "çalışma zamanı istisnası yok" ile kastettiğidir :)
Andres F.

@Benim toprak yıkıcı olmadığını kabul ediyorum. Çalışma zamanı istisnaları arasındaki fark, türlerde açık olmamalarıdır (yani, kaynak koduna bakmadan bir kod parçasının fırlayıp fırlayamayacağını bilemezsiniz); türlerdeki hataları kodlamak çok açıktır ve programcının bunları gözden kaçırmasını önleyerek daha güvenli bir kod sağlar. Bu, birçok FP dili tarafından yapılır ve gerçekten yeni bir şey değildir.
Andres F.

1
Yorumlarınıza göre "statik tip kontroller" den daha fazlası olduğunu düşünüyorum . JS'yi yeni bir "yap ya da kır" ekosisteminden çok daha az kısıtlayıcı olan Typescript'i kullanarak ekleyebilirsiniz.
16'da

1
@AndresF .: Teknik olarak, Java'nın tip sisteminin en yeni özelliği, 60'ların sonlarını oluşturan Parametrik Polimorfizm'dir. Yani, bir anlamda, "Java değil" demek istediğinizde "modern" demek biraz doğrudur.
Jörg W Mittag

0

Elm iddia ediyor:

Uygulamada çalışma zamanı hatası yok . Boş değil. Tanımlanmamış hiçbir işlev değildir.

Ancak çalışma zamanı istisnalarını soruyorsunuz . Bir fark var.

Elm'de hiçbir şey beklenmedik bir sonuç döndürmez. Elm'de çalışma zamanı hataları üreten geçerli bir program yazamazsınız. Bu nedenle, istisnalara ihtiyacınız yoktur.

Yani soru şu olmalıdır:

"Çalışma zamanı hatası yok" un faydası nedir?

Asla çalışma zamanı hataları olmayan bir kod yazabilirseniz, programlarınız asla çökmez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.