» »

Vprašanji glede napak pri programiranu

Vprašanji glede napak pri programiranu

deejay2 ::

Zanima me nekaj glede razredov izjem (exceptions), ki vsebujejo napake pri Visual Basicu.. Na eni sliki gledam hierarhijo teh razredov izjem, kjer je zgorej razred Object (v katerega spadajo Equals, GetType, ToString), takoj pod njim pa je razred Exception, pod njim pa je še en kup drugih, kot na primer IOException, FormatException... U glavnem, zanima me, kaj ta taprvi Object razred predstavlja sploh? A je to sploh razred napak, ali je prvi razred, ki ima v sebi opise napak, šele Exception? Upam, da sem razumljivo povedal :).

Še tole me zanima. Naredil sem en programček za računanje. Enkrat sem v kodo napisal, da naj lovi morebitno napako iz razreda Exception (Catch izjema As Exception itd), drugič pa, da naj jo lovi iz razreda OverflowException (Catch izjema As OverflowException itd). Ko sem pognal program sem namerno naredil napako, tako da sem kot vnos vpisal predolgo številko...vpisal sem recimo 400000000000000000000 in je javlo napako. V obeh primerih je vrglo isto napako, in sicer "overflow". Zdaj me pa zanima, v čem je sploh prednost navajanja natančnejšega razreda napak (kot so na primer omenjeni OverflowException, IOEException, FormatException...), ko jih loviš s Catch-om, če ti pa vrže isto napako ven kot v zgornjem primeru?

fiction ::

U glavnem, zanima me, kaj ta taprvi Object razred predstavlja sploh? A je to sploh razred napak, ali je prvi razred, ki ima v sebi opise napak, šele Exception? Upam, da sem razumljivo povedal :).
Object je nek skupen prednik vseh objektov (koren v hierarhiji dedovanja). Kakrsenkoli razred / strukturo naredis bo ta implicitno dedovala od object ali pa eksplicitno od nekega njegovega naslednika. Pri cemer za razliko od Jave v .NET-u tudi int izhaja iz object.

Object ima recimo metodo ToString(), kar pomeni, da poljuben objekt lahko prikazes kot niz znakov. Po defaultu je to narejeno na en nacin, lahko pa pri svojem konkretnem razredu to metodo overridas, da naredi nekaj bolj smiselnega.

Napake se zacnejo sele z Exception. Sicer teoreticno lahko meces oz. lovis tudi zadeve, ki niso izpeljane iz Exception, ampak to ni ravno priporocljivo.

Zdaj me pa zanima, v čem je sploh prednost navajanja natančnejšega razreda napak
Vse je odvisno od tega kaj hoces. Naceloma naj bi ulovil samo tisto kar znas pohandlati. Ce lovis Exception bos dobil npr. poleg OverflowException tudi NullReferenceException ali kaj tretjega (vse kar je izpeljano iz Exception: OverflowException je se vedno Exception).

Problem je v tem, da si OverflowException pricakoval in znas nekaj smiselnega narediti tudi ce pride do tega, ampak pri NullPointerException bi bilo pa mogoce kaj drugega boljse. Recimo povedati metodi iz katere se je klicala trenutna metoda, da je do tega prislo, kar je z exceptioni precej enostavno. Ce ne bi ujel NullReferenceException izjeme, bi avtomaticno dobila klicoca metoda moznost, da ujame exception in tako naprej. Ko enkrat stvar pride cisto do vrha brez da bi jo kdo ustavil, se program razsuje. Ampak to ni tako kriticno, kot ce nekje zanalasc ujames izjemo, brez da bi jo znal smiselno resiti. V takem primeru se ti recimo lahko unici neko stanje v programu: ta se sicer ne neha izvajati, ampak zacne delovati nepredvidljivo narobe, kar je precej huje.

Torej: najbolje je ujeti najmanj specificni tip Exceptiona, ki ga pricakujes in vedno, ko nekaj ujames, to tudi ustrezno logirati. Ce samo "pojes" Exception ti to lahko pri debuggiranju zakaj nekaj ne dela, lahko povzroci precej sivih las.

Zgodovina sprememb…

  • spremenil: fiction ()

deejay2 ::

Hm za razlago, ampak mi ni še čisto jasen tale zadnji del o izjemah. V eni knjigi je, če se ne motim, pisalo tako, da če pričakuješ eno specifično napako, je bolje, če jo loviš s specifičnim razredom, če pa ne veš, katero napako pričakovati, daš pa glavni Exception. Ti praviš ravno obratno, da naj se raje uporablja kar glavni Exception?

Drugače pa pišem to za eno seminarsko nalogo. Sta ti dve trditvi, ki sem ju navedel v njej, pravilni spodej?
-Zelo dobro pri načinu strukturnega obravnavanja napak (z Exception razredi) je, da lahko sami pripeljemo do uporabnika opis napake, ki mu natančneje pove, kaj je storil narobe.
-Namen podrazredov glavnega razreda Exception je, da vsebujejo še dodatne informacije o napaki.

darkolord ::

Ti praviš ravno obratno, da naj se raje uporablja kar glavni Exception?
Nikoli! (no, zelo zelo redko)

Exceptione se v glavnem uporablja tam, kjer se lahko zadeva sesuje zaradi (zunanjih) faktorjev, ki jih nimaš pod kontrolo oziroma jih ne moreš (enostavno) preverjati (file, network, database I/O)

deejay2 ::

Aha tenx. Kaj je pa potem glavna prednost tega strukturiranega obravnavanja napak s temi Exception razredi (predvsem v primerjavi s starim GoTo načinom za napake)?

noraguta ::

u bistvu maš prav z tem goto, gre za to , da omogoča zadeva neke vrste control flow, se pa najbi temu izogibali(v smislu intenzivne uporabe izjem za control flow) , ker so izjeme napram goto-ju ogabno počasne(smo že lobirali pri ms-ju naj v clr vključi nek lightweght mehanizem v stilu lisp signalov, saj bi stem in general proftirali vsi funkcijski jeziki). so pa izjeme strukturirane in varne(ujet exception ti ne bo porušil aplikacije). btw določene izjeme seveda tudi sporočijo operacijskemu sistemu kaj storit.
Pust' ot pobyedy k pobyedye vyedyot!

Zgodovina sprememb…

  • spremenilo: noraguta ()

BlueRunner ::

Aha tenx. Kaj je pa potem glavna prednost tega strukturiranega obravnavanja napak s temi Exception razredi (predvsem v primerjavi s starim GoTo načinom za napake)?

Poskusi z GoTo sporočiti napako klicatelju metode, pa boš videl zakaj to ne gre.

Poskusi kakorkoli sporočiti klicatelju, da je prišlo do napake pri konstrukciji novega objekta.

Izjeme ti omogočajo obraavnavanje izjemnih dogodkov, ki se sicer lahko pripetijo, hkrati pa to ni nek pričakovan dogodek. Razlika med izjemnim in pričakovanim dogodkom je ta, da se pri izjemnem delovanje aplikacije tipično ne bo moglo nadaljevati, ali pa bo nadaljevanje možno samo po opravljenih izravnalnih korakih.

Ker se posredujejo izven glavnega logičnega toka, pa to pomeni, da ti ni potrebno vseh metod obremenjevati še z dodatnimi parametri, preko katerih se bo klicateljem sporočalo izjemne dogodke. V nekateri primerih (konstrukcija objektov) pa posredovanje statusa preko parametrov sploh ni možno. Zato so izjeme v OO jezikih privzeto vgrajene. Ker drugače (načeloma) ne gre.

noraguta ::

Poskusi z GoTo sporočiti napako klicatelju metode, pa boš videl zakaj to ne gre.

Poskusi kakorkoli sporočiti klicatelju, da je prišlo do napake pri konstrukciji novega objekta.

huh si mi pa vrgel kost, moram še mal obnovit tele zadeve ampak na hitro.
tam dol (libc-hw nivo) ni izjem. na win sta naknadno maštrikana seh in veh(od xpsp2 se mi zdi). in veh je praktično gledano kar lep približek handlanja napak z goto-jem. hudič je , da clrjev mehanizem prvenstveno bazira na seh ter javinem pristopu.http://blogs.msdn.com/jmstall/archive/2...

veh sam po sebi ne more bistveno spremenit obravnavanja napak v clr , ker je zato potrebno priredit runtime. šele tedaj bi lahko izjeme oz mehanizem , kateri bi pokrival tudi izjeme deloval učinkovito za vsakršen control flow. sem pa stvari že rahlo pozabil tako da naj me kdo popravi če sem se zmotil.
Pust' ot pobyedy k pobyedye vyedyot!

BlueRunner ::

Errr... izjeme so na tem svetu že od pamtiveka. Nekateri procesorji so izjemo (npr. deljene z 0) sporočili s prekinitvijo izvajanja programa in skokom na poseben naslov - interrupt. POSIX je stvar kodificiral v obliki signalov, s katerimi OS prekine normalen tok programa in izvjanje nadaljuje na posebni kodo, ki obravnava posamezne signale. VEH je nadaljevanje zgodbe POSIX signalov, SEH pa je način kako oblvadovati sistemske napake v Win32.

Ne vem pa kaj si želel povedati s tem, da obravnava izjem v CLR bazira na SEH in Javi. Mono CLR, ki deluje na POSIX sistemih ne uporablja SEH, ker ta tam ne obstaja, obstajajo pa signali, zaradi česar lahko Mono prestreže SIGSEG tako, kot MSCLR lahko prestreže 0xc0000005. Kar se tiče sintakse sta C# in VB.NET sintaksi podobni Javi, ta je podobna C++, C++ pa si je marsikaj sposodil od Ade. Po drugi strani pa imaš na voljo tudi Eiffel.net, ki se ravno tako prevede v CLR, hkrati pa je njegova semantika obvladovanja izjem čisto drugačna od C#-ove. Torej CLR-jev mehanizem sam po sebi ne predpisuje kakšna bo semantika obravnave izjeme.

Če pa si želel povedati samo to, da CLR z VEH ne more delovati, pa pač je****... to se zgodi, ko se poskuša managed kodo poriniti vsepovsod tam, kamor morda tudi ne spada. Managed koda pač spada v managed svet, unamanaged v unamaged, pohajkovanje med tema dvema pa naj bo minimalistično in omejeno. VEH pač ne sme uporabljati managed kode in to je to. Glede na to, da se ga lahko pokliče kadarkoli, je to popolnoma razumljivo. Sicer pa tudi ne vem kdo pri zdravi pameti bi želel uporabljati VEH callback, ki kliče managed kodo. To je preprosto KatastrofalnoSlabaIdeja™.

noraguta ::

Interupti so prekinitve, izjeme so pa excetioni, mislim da sva se tu zgrešila.

Glede drugačne semantike je pa ravno pri implementaciji problem ker je boleče počasen, če probaš stlačit signale in izjeme v enoten mehanizem, seveda lahko vse povoziš. Seveda lahko vse povoziš ampak potem si povsem na svojem pozabi, da ti bo koristil obstoječ debuger in ostala infrastruktura katero ti framework nudi.
Pust' ot pobyedy k pobyedye vyedyot!

Zgodovina sprememb…

  • polepsal: Mavrik ()

fiction ::

Ti praviš ravno obratno, da naj se raje uporablja kar glavni Exception?
Tega nikoli nisem rekel - celo obratno, da je bolje uloviti bolj specificen exception (kot presiroko mnozico kar naredis z Exception).

Kot je rekel Dijkstra: goto, naj se ne bi uporabljal. Obstaja precej malo primerov, kjer se da njegovo uporabo zagovarjati.
Za simuliranje mehanizma izjem ni primeren, ker tako ne mores skociti v drugo funkcijo. Za klic je potreben klicni zapis na skladu in kontroliran skok na podprogram oz. povratek iz njega, ne samo to, da procesor zacne izvajati kodo, ki je nekje drugje.

Z discipliniranim programiranjem lahko enostavno simuliras izjeme. Najbolj primitivno tako, da pac funkcija vrne namesto rezultata se nek error code. Tezava pri tem je, da koda hitro postane nepregledna. V C-ju je zato bolje uporabiti setjmp() / longjmp() funkciji. Drug problem je pa, da je tezko v neki klicoci funkciji sprostiti vire, ki jih je alocirala klicana funkcija.

Zanimiv primer exception handlinga ima recimo Symbian (link). Tam je v bistvu vse skupaj reseno s tem, da funkcija lahko "leava" kar pomeni nekaj takega kot vrze exception. Potem imas se TRAP() makre, kot nekaksen catch. Drugo je pa "clean-up stack",
kjer so stvari, ki jih je se treba dealocirati in sicer lepo po vrsti od zadnje do prve.

fiction ::

Kar se tice SEH. A ni to samo nek povezan seznam v katerega so vkljuceni handlerji ("metode ki izvajajo catch blok")?
Ta utility bi sicer low-level programer lahko uporabljal cisto po svoje, ampak prevajalnik ponavadi zato, da ima manj dela vse skupaj zlorabi in v naprej pripravi glede na to kje imas vse catch seznam ala C->B->A->X. Ko pride do exceptiona se v bistvu najprej poklice C in ce je ta uspel servisirati izjemo je ok, sicer se poklice B in tako naprej. X je pa neka rezervirana (default) funkcija, ki prekine izvajanja programa (ce ni nikogar, ki bi ujel izjemo).

V casu izvajanja je vse skupaj, ker pri prevajanju ni jasno, ali ne bo mogoce zaradi kaksnega
if (random) throw;
C "spustil" izjemo naprej.

Signal handler je pac samo ena funkcija, ki je odgovorna za napake dolocene vrste. Ampak se vedno lahko sam naredis ta dispatch.

fiction ::

-Zelo dobro pri načinu strukturnega obravnavanja napak (z Exception razredi) je, da lahko sami pripeljemo do uporabnika opis napake, ki mu natančneje pove, kaj je storil narobe.
Ni nujno, da je uporabnik naredil karkoli narobe. Ce pricakujes kaj takega, raje preverjaj vhod in v primeru, da ni dober, to povej uporabniku cisto brez uporabe izjem. Exceptioni so razmeroma pocasni.

Tipicen primer uporabe izjem je recimo izpad mrezne povezave. Namesto, da vedno reces "ce je se mrezna povezava, naredi to", reces "delaj vse to in v primeru, ce slucajno ni mrezne povezave (kar je precej malo verjetno), odreagiraj tako".
Za nek 3rd party library ne mores dodati nekih svojih posebnih preverjanj. Lahko pa pustis da dela tako kot dela, ulovis njegove izjeme in jih na svoj nacin pohandlas.

-Namen podrazredov glavnega razreda Exception je, da vsebujejo še dodatne informacije o napaki.
Jaz bi raje sel obratno. "Podrarazredi" predstavljajo posamezen tip napake oz. tega kaj je slo narobe. Smiselno so zdruzeni v neke vecje enote in v koncni fazi v Exception, ki predstavlja kakrsnokoli mozno napako. V Exception so samo najbolj splosni podatki, medtem ko imajo podrazredi se dodatne atribute, ki so smiselni za dolocen tip napake.

BlueRunner ::

Interupti so prekinitve, izjeme so pa excetioni, mislim da sva se tu zgrešila.

Sva in nisva. Prekinitve so tudi mehanizem obveščanja o izjemah. So pa hkrati (x86 arhitektura) tudi mehanizen obveščanja o dogodkih in mehanizem klicanja funkcij v OS. Zato prekinitve štejem tudi kot način obravnave in implementacije izjem, pa čeprav se lahko z njimi počne še marsikaj drugega.

stlačit signale in izjeme v enoten mehanizem, seveda lahko vse povoziš. Seveda lahko vse povoziš ampak potem si povsem na svojem pozabi, da ti bo koristil obstoječ debuger in ostala infrastruktura katero ti framework nudi

To imaš čisto prav. Sam pa k temu dodam samo še to mnenje, da razvoj v managed okolju praviloma pomeni, da boš imel z unamanged okoljem minimalne stike, če sploh. xVM pa mora poskrbeti za pravilno semantiko delovanja s posebnostmi, kot jih pozna podležen OS. Zato določenih stvari pač ne počneš... zame osebno se to potem zreducira na ugotavljanje katero orodje je primerno in katero ni. Managed okolje pač ni vedno in za vse primerno, pa če si ga bi še tako zelo želel zaradi njegovih dobrih lastnosti.

Za simuliranje mehanizma izjem ni primeren, ker tako ne mores skociti v drugo funkcijo.

Hkrati pa je zelo primeren za emuliranje izjem, kakršne pozna Eiffel, saj ti velikokrat omogoča bolj jasno izražanje logike delovanja, kot je pa to možno z uporabo zanke. Vendar pa to seveda zapade pod "izjemo, ki potrjuje pravilo".

Z discipliniranim programiranjem lahko enostavno simuliras izjeme.

S tem se sploh ne bi strinjal. Čeprav lahko res na delu kode uvedeš standardne parametre preko katerih posreduješ OOB podatke, pa je to delo tako zelo mukotrpno, da so še celo avtorji Cfront obupali in zgodbo opustili. Preprosto ni bilo vredno časa pisati kodo na določen način, če lahko to delo prevajalnik opravi mnogo bolje. Če bi želel uporabljati izjeme "na roke", potem bi to pomenilo točno to: ročno pisanje kode na določen način.

-Namen podrazredov glavnega razreda Exception je, da vsebujejo še dodatne informacije o napaki.

Jaz bi raje sel obratno. "Podrarazredi" predstavljajo posamezen tip napake oz. tega kaj je slo narobe.

Oba imata prav. Rekel bi celo, da imata na žalost oba prav. Na žalost pa zato, ker so med knjižnicami in tudi znotraj standardnih knjižnic, tako za Java, kot za C#, oba pristopa pomešana. Včasih imam razred, ki s seboj nosi dodaten podatek, ki pove kakšna je bila dejanska vsebina izjeme, včasih pa imam množico razredov, ki vsak zase označujejo samo eno možno vsebino izjeme. Oba načina sta popularna, oba se uporabljati in reči, da je en bolj "pravilen" od drugega IMHO ni možno. Spopadati se moraš pač z obema.

Looooooka ::

Mnja...lastni exceptioni naj bi izhajal iz ApplicationException.Vsaj tko priporocajo pri microsoftu.
Pa ze zato je dobr, da lahko nardis en globaln handler, ki lovi framework napake in tvoje lastne application napake.
God forbid, da vsakic nardis samo "throw new Exception("ZOMFG!").
Btw...ce mas narjeno neko funkcijo, ki nekaj preverja in je ob negativnem rezultatu mogoce pricakovati Exception...(ti pa bos recimo vracal samo true/false) se splaca pred tisto funkcijo dodati atribut
<System.Diagnostics.DebuggerNonUserCode()> _
oz v c#
[global::System.Diagnostics.DebuggerNonUserCode]
.
Tako, ti debugger ne bo metal exceptionov, ki jih tako ali tako pricakujes in te dejansko ne zanimajo, ker niso "napaka".

noraguta ::


Tako, ti debugger ne bo metal exceptionov, ki jih tako ali tako pricakujes in te dejansko ne zanimajo, ker niso "napaka".
pa saj se da tudi v debugerju poklikat filter (v bistvu ti potem on inlina kodo. kakor lahko tudi breakpoint postaviš povsem programsko.
Pust' ot pobyedy k pobyedye vyedyot!

Looooooka ::

Mene osebno zanimajo vsi exceptioni razen tistih, ki me ne...ergo NonUserCode.Vse ostale hocem, da se dvignejo...ker zna bit njihov obstoj bit posledica moje kode....in ne povezave do baze...http streznika in podobnega.
Drugace pa ja...lahko lepo poklikas ce se ti da :)

noraguta ::

evo tole je nekako tako utopično razmišljanje , kot bi si ga uporabnik(programer želel).
http://matija.pretnar.info/the-logic-an...
Pust' ot pobyedy k pobyedye vyedyot!


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

Applov nov programski jezik Swift (strani: 1 2 )

Oddelek: Novice / Apple iPhone/iPad/iPod
7231688 (26249) Kocka
»

[visual C#] Na drugem računalniku se ne zažene

Oddelek: Programiranje
121528 (1358) Beezgetz
»

Kdaj uporabiti izjeme?

Oddelek: Programiranje
241628 (1509) Gundolf
»

[C#] Izhod iz funkcije

Oddelek: Programiranje
211303 (1129) MaCoFaCo
»

Coding Style

Oddelek: Programiranje
433306 (2498) 64202

Več podobnih tem