Toon posts:

[c++] geen exception-upcasting door specificatie?

Pagina: 1
Acties:
  • 118 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Sorry voor de onduidelijke topictitel; ik kon er echt niks beters van maken..

Maargoed, ik was eens aan het spelen met exception specificaties:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

struct A {};
struct B : A {};

void f () throw (A)
{
  throw B();
}

int main ()
{
  try
  {
    f();
  }
  catch (B)
  {
    std::cout << "B";
  }
}

Bij het uitvoeren werd de catch(B) handler aangeroepen. Dit betekent dus dat de exception zijn afgeleide type B niet verloor, ondanks f's throw(A) exception specificatie.

Dit verbaaste me; het leek me logischer wanneer de exception alleen nog maar opgevangen kon worden als een A vanwege f's exception specificatie.

Dus, hoort dit zo of zit mijn compiler (Borland C++ 5.6) ernaast ?


Edit:
MSVC++ 6.0 doet hetzelfde, dus het zal wel zo horen.. Ik blijf het overigens vreemd vinden, dus commentaar blijft zeer welkom. :)

  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Volgens mij garanderen exceptie specificaties alleen dat een functie/methode (alleen) de opgegeven excepties kunnen throwen, en wordt er niet gecontroleerd wat je catch't, zoals dat bij Java wel het geval is.

Trouwens, ik krijg een warning als ik dit probeer te gebruiken in MS VC++: warning C4290: C++ Exception Specification ignored.

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Ik vind dit wel logisch van de compiler.

Exception B is een A. De throw is dus valid.
Vervolgens wil je alleen B ontvangen, die wordt ook gegooid en dus opgevangen.

Stel je zoiets voor als dit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void OpenFile() throw (IOException)
{
  ...
  throw FileNotExist();
  ...
}

int main()
{
  try
  {
     OpenFile();
  }
  catch(FileNotExist)
  {
     cout << "Selecteer een ander bestand" << endl;
  }
  catch(IOException)
  {
     cout << "Onbekende fout opgetreden" << endl;
     return;
  }
}

Ik vind dit een nette manier om te werken.

Verwijderd

Topicstarter
Hmm, het wordt tijd dat ik de implementatie van de exception-mechanismes eens een keer doorneem; ik weet eigenlijk totaal niet hoe ze werken en daardoor ga ik rare dingen verwachten ;).

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Op zondag 09 juni 2002 23:24 schreef Sneechy het volgende:
Hmm, het wordt tijd dat ik de implementatie van de exception-mechanismes eens een keer doorneem; ik weet eigenlijk totaal niet hoe ze werken en daardoor ga ik rare dingen verwachten ;).
Ik moet eerlijk zeggen dat ik in C++ nooit gebruik heb gemaakt van het aangeven welke excepties worden gegooid, en wist ook niet dat dit kon. Waarom is dit? Ze dwingen het toch niet af?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Als de exception een 'andere A' is dan B zal de fout simpelweg niet worden opgevangen op deze plaats...

Je vangt alleen een B op en dat heeft verder eigenlijk maar weinig met het gooien van de A te maken.

Dit is dus iets heel anders dan een vergelijkbaar iets in een methode aanroep, waardoor je vraag waarschijnlijk wordt veroorzaakt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Test {
  public static void main(String[] ps) {
    new Test().test();
  }

  public void test() {
    doSomething(getValue());
  }

  public A getValue() {
    return new B();
  }

  public void doSomething(A a) {
    System.err.println("a");
  }

  public void doSomething(B b) {
    System.err.println("b");
  }
}

class A {
}

class B extends A {
}

Je ziet hier het effect van een methode aanroep waarop er alleen op het eerste argument van een methode aanroep wordt gedispatched, welke in Java dus niet zichtbaar is omdat dat de klasse zelf is.

De oplossing voor dit probleem is een Visitor achtig pattern of multi-methods/double-dispatch als de gebruikte taal dit ondersteunt. Bij multi-methods wordt er niet alleen gedispatched op de ontvanger (het eerste argument) maar op meerdere of alle argumenten van een methode.

Bij exception afhandeling ligt dit anders: er wordt als het ware niet 'gedispachted' op het statische bekende type van de exception, maar op het runtime bekende type: als een exception echt een B is ipv een A, zal deze opgevang worden door het catch blok die een B exception opvangt.

Het fraaie hiervan is dat je dus specifieke exceptions kunt opvangen en andere kunt doorgooien of in een ander catch-blok kunt opvangen.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • ^Mo^
  • Registratie: Januari 2001
  • Laatst online: 04-11-2025
Op zondag 09 juni 2002 22:59 schreef marcusk het volgende:
Volgens mij garanderen exceptie specificaties alleen dat een functie/methode (alleen) de opgegeven excepties kunnen throwen, en wordt er niet gecontroleerd wat je catch't, zoals dat bij Java wel het geval is.

Trouwens, ik krijg een warning als ik dit probeer te gebruiken in MS VC++: warning C4290: C++ Exception Specification ignored.
Klopt, de microsoft compiler negeert dit soort constructies gewoon (zie ook hier: http://gathering.tweakers.net/forum/list_messages/516731)

"There are 10 kinds of people in the world, those who understand binary and those who don't" | Werkbak specs


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Orphix: Waarom is dit?
Het lijkt mij positief als je aangeeft welke exceptions een methode zou kunnen gooien. Je biedt de aanroepende methode zou de garantie dat je code in principe alleen maar deze exceptions kan gooien, waardoor je dus beter de correctheid van code en de fouten die opgevangen zouden moeten worden kunt zien. Ik zie het dus als een waardevolle uitbreiding van de declaratie van een functie...

De compiler kan zo eventueel ook meer controleren of optimaliseren en eventueel waarschuwingen geven als exceptions niet op worden gevangen (weet niet of de compiler dat verplicht is eigenlijk).

Als je code toch een andere exception gooit hoor je eigenlijk een serieus probleem te hebben (zie 14.6 Exception Specifications, Bjarne Stroustrup ).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Orphix
  • Registratie: Februari 2000
  • Niet online
Ik vind ook dat het aangeven van excepties erg makkelijk is voor de gebruiker van de functie (en waarschijnlijk ook voor de compiler). Toch zie je het niet vaak in C++, jammer want het zou misschien helpen om het toch beetje ondergeschoven kindje in C++ consequenter toe te passen.

Al zie ik C++ programmeurs nog wel in staat om dit te doen
code:
1
2
3
void DoeIets() throw(...)
{
}

>:) geen idee of dit geldige syntax is!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

de exception specificatie geeft aan welke types gethrowed moeten worden, maar ook afgeleiden van die types mogen gethrowed worden (en dus niet specifiek die types die je hebt aangegeven)

zie ook sectie 15 van de ANSI C++ draft :)

bovendien, hoe zou ie z'n type dan kunnen verliezen? Stel dat B een A 'wordt', als A virtual functies heeft die zijn override door B, en je roept die aan via A, dan worden dus nog steeds de B functies aangeroepen. Terwijl het een A is, wat dus niet klopt. Iets kan z'n type niet verliezen imho

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: bovendien, hoe zou ie z'n type dan kunnen verliezen?
Ik denk dat die opmerking volgt uit het de single-dispatch bij een methode aanroep, zoals de code die ik postte laat zien...

Met 'niet verliezen' wordt dus in feite bedoeld (denk ik ;) ) dat het opvangen van een exception niet gebeurd op basis van de gedefinieerde, statische bekende, type van de exceptie (zoals in de methode aanroep dus wel), maar op basis van het daadwerkelijke type van de exception.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

ah op die fiets
maar ja, imho is dat niet echt logisch, want dan wordt de catch handler van B in het voorbeeld niet aangeroepen, terwijl het feitelijk wel een B is

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:42
Op maandag 10 juni 2002 00:02 schreef .oisyn het volgende:
Iets kan z'n type niet verliezen imho
Ik was altijd in de veronderstelling dat zowel C als C++ niet zoiets kenden als run-time types. Je kunt, voor zover ik weet, in C++ niet opvragen wat de 'werkelijke' klasse van een object is (de klasse die geinstantieerd werd dus).

Alles wat met typen te maken heeft, wordt tijdens het compileren afgehandeld, wat naar mijn mening een erg sterk punt is, omdat het ontwerpen die afhankelijk zijn van het casten naar derived typen ontmoedigt (aangezien er eigenlijk geen veilige manier is om dit te doen). In Java wordt dit nog wel eens gedaan en ik vind het bijna altijd lelijke oplossingen.

Ik ben dus nogal verbaasd dat hiet blijkbaar wel runtime typeinformatie overgedragen wordt en vraag me dus, net als Sneechy, af hoe dit (doorgaans) geïmplementeert is. Het lijkt me nauwelijks efficiënt af te handelen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: maar ja, imho is dat niet echt logisch
Tja, maar de situatie hierboven (single-dispatch) kan je dat wellicht ook onlogisch vinden terwijl het daar juist de situatie is die jij voor het opvangen van exceptions onlogisch vindt ;) . Met andere woorden: als je dit logisch vindt, is single-dispatch onlogisch.

Uiteraard zijn we single-dispatch wel gewend en gaan exceptions ten slotte om uitzonderlijke situaties, dus eigenlijk is de vergelijking niet zo er goed, maar wel treffend ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Topicstarter
Op maandag 10 juni 2002 00:30 schreef Soultaker het volgende:
Je kunt, voor zover ik weet, in C++ niet opvragen wat de 'werkelijke' klasse van een object is (de klasse die geinstantieerd werd dus).
Kan wel: C++ heeft RTTI (zie Google voor meer informatie).

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:42
Op maandag 10 juni 2002 00:30 schreef mbravenboer het volgende:
Tja, maar de situatie hierboven (single-dispatch) kan je dat wellicht ook onlogisch vinden terwijl het daar juist de situatie is die jij voor het opvangen van exceptions onlogisch vindt ;) . Met andere woorden: als je dit logisch vindt, is single-dispatch onlogisch.
Dit kan ik niet helemaal volgen (niet alleen door de vage zinsconstructies). Wat noem je precies een 'single-dispatch situatie'?

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:42
Op maandag 10 juni 2002 00:33 schreef Sneechy het volgende:
Kan wel: C++ heeft RTTI (zie Google voor meer informatie).
Google brengt me naar allerlei vage Finse en Japanse websites, maar voor zover ik kan beoordelen, is RTTI een extentie in bepaalde libraries en compilers en (gelukkig) geen onderdeel van de C++ standaard. Ik ben nog geen situatie tegengekomen waarin run-time types noodzakelijk waren voor een elegante oplossing en ik vermoed dat die situaties ook niet bestaan.

* Soultaker krijgt steeds meer aandrang om eens te investeren in Stroustrup's "The C++ Programming Language", om dit soort dingen goed te kunnen uitzoeken. Jammer dat die boeken altijd zo duur zijn. :(

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Soultaker: niet alleen door de vage zinsconstructies.
Sorry ;) .
Wat noem je precies een 'single-dispatch situatie'?
Als er alleen het eerste argument van een methode aanroep wordt gedispatched (bepaald welke methode er echt aangeroepen moet worden). Dit is de ontvanger van de methode aanroep: de klasse die de methode bevat. Het gevolg zie je hierboven in mijn code: de methode met A als argument wordt aangeroepen en niet de methode met B, terwijl het wel een B is. Bij multi-methods of double-dispatch wordt het type van de tweede argument (zichtbaar dus het 1e) wel meegenomen...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Soultaker: Het lijkt me nauwelijks efficiënt af te handelen.
Het is gelukkig ook een uitzonderlijke situatie ;) .

Over implementatie, ik vond zo snel even dit:
http://www.codeproject.com/cpp/Exceptionhandler.asp
en dit:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndeepc/html/deep070199.asp

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Op maandag 10 juni 2002 00:38 schreef Soultaker het volgende:
Google brengt me naar allerlei vage Finse en Japanse websites, maar voor zover ik kan beoordelen, is RTTI een extentie in bepaalde libraries en compilers en (gelukkig) geen onderdeel van de C++ standaard. Ik ben nog geen situatie tegengekomen waarin run-time types noodzakelijk waren voor een elegante oplossing en ik vermoed dat die situaties ook niet bestaan.
Het typeid keyword is standaard ANSI C++. Zie Handige ANSI C++ draft.

Verwijderd

Topicstarter
Op maandag 10 juni 2002 00:44 schreef marcusk het volgende:
Het typeid keyword is standaard ANSI C++.
En dynamic_cast is ook echt standaard C++.

Soultaker: Het gaat hier dus niet om rare extensie-libs, RTTI is een wezenlijk onderdeel van C++.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:42
Op maandag 10 juni 2002 00:43 schreef mbravenboer het volgende:
Als er alleen het eerste argument van een methode aanroep wordt gedispatched (bepaald welke methode er echt aangeroepen moet worden).
Ah, nu begrijp ik 't beter. Het lijkt me niet zozeer een verschil tussen het aantal argumenten waarnaar 'gekeken' wordt, maar meer of er bij het compilen of bij het runnen naar gekeken wordt.

Het bepalen van het doel van een methode (single-dispatch dus) is tijdens het compileren te doen (in principe zelfs bij dynamische gebonden/virtuele methoden). Het vinden van het juist catch-block in het voorbeeld van sneechy is duidelijk iets wat niet bij het compileren kan worden uitgewerkt (of ik moet iets over het hoofd zien).

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 19:42
Op maandag 10 juni 2002 00:47 schreef Sneechy het volgende:
En dynamic_cast is ook echt standaard C++.

Soultaker: Het gaat hier dus niet om rare extensie-libs, RTTI is een wezenlijk onderdeel van C++.
Sorry voor mijn domme opmerkingen; I stand corrected. ;(

(Voor mijn excuus: zie mijn commentaar betreffende Stroustrup.)

Wel jammer trouwens, ik vond dit altijd een sterk punt van C++ (en m'n punt betreffende de nutteloosheid van runtime type informatie blijft).

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

heb even wat geprobeerd, en dat veranderde mijn standpunt behoorlijk :)
Op zondag 09 juni 2002 23:30 schreef mbravenboer het volgende:
Bij exception afhandeling ligt dit anders: er wordt als het ware niet 'gedispachted' op het statische bekende type van de exception, maar op het runtime bekende type: als een exception echt een B is ipv een A, zal deze opgevang worden door het catch blok die een B exception opvangt.
dat is dus niet zo

in C++:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {};
class B : public A {};

int main ()
{
    try
    {
      B b;
      throw (A)b;
    }
    catch (B)
    {
    }
    catch (A)
    {
    }
};

hier zal de catchhandler van A worden aangeroepen, ipv die van B (wat ik dus zo onlogisch vond ;))

waardoor ik ook gelijk begrijp waarom Sneechy die vraag stelt :) Maar goed, mijn antwoord blijft hetzelfde: namelijk dat je niet per se een A mag throwen maar ook een afgeleide van A, zo zit de exception specification nou eenmaal in elkaar

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Op maandag 10 juni 2002 00:47 schreef Sneechy het volgende:
En dynamic_cast is ook echt standaard C++.
Wat bedoel je daarmee? Dat is het toch ook ? :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op maandag 10 juni 2002 00:54 schreef marcusk het volgende:

[..]

Wat bedoel je daarmee? Dat is het toch ook ? :)
dynamic_cast heeft runtime type information nodig om te kijken of en hoe de cast mogelijk is

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Soultaker: maar meer of er bij het compilen of bij het runnen naar gekeken wordt.
Dat is het eigenlijk niet, het is meer de vraag of er naar gekeken wordt of niet.
Het bepalen van het doel van een methode (single-dispatch dus) is tijdens het compileren te doen (in principe zelfs bij dynamische gebonden/virtuele methoden).
Nee, bij single-dispatch wordt de moeite genomen om at runtime de omschrijving van de klassen te raadplegen om te bekijken welke methode er aangeroepen moet worden. Dit klinkt natuurlijk onwijs omslachtig, maar dat valt wel iets mee omdat het natuurlijk enorm geoptimaliseerd geimplementeerd wordt en bij veel methode aanroepen zelfs weg-geoptimaliseerd kan worden.

Bij multi-dispatch wordt er nog meer moeite gedaan en wordt er dus niet alleen naar het eerste argument gekeken (de klasse), maar ook naar de andere argumenten. Dit kost uiteraard performance.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Op maandag 10 juni 2002 00:58 schreef mbravenboer het volgende:
Nee, bij single-dispatch wordt de moeite genomen om at runtime de omschrijving van de klassen te raadplegen om te bekijken welke methode er aangeroepen moet worden. Dit klinkt natuurlijk onwijs omslachtig, maar dat valt wel iets mee omdat het natuurlijk enorm geoptimaliseerd geimplementeerd wordt en bij veel methode aanroepen zelfs weg-geoptimaliseerd kan worden.

Bij multi-dispatch wordt er nog meer moeite gedaan en wordt er dus niet alleen naar het eerste argument gekeken (de klasse), maar ook naar de andere argumenten. Dit kost uiteraard performance.
Ik dacht ook dat het was zoals Soultaker zegt. Neem dit voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
class A { ... }
class B : A { ... }
...
void f(A) { ... }
void f(B) { ... }
...
A x = new B();
B y = new B();

f(x); f(y);

Dan wordt toch in het eerste geval f(A) en in het tweede geval f(B) aangeroepen? (Anders zou het visitor pattern een beetje nutteloos zijn lijkt me) :? Dus er wordt niet at-runtime gekeken naar het type van x; dan zou immers f(B) aangeroepen worden.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: dat is dus niet zo
Hum..... dat is maf :o .

Volgens mij is dit niet compatible met de beschrijving in het boek van Stroustrup (14.3.2.1: Order of Handlers): daar staat namelijk dat de handlers op volgorde geprobeerd worden. Dat is hier dus niet het geval :( .

Als in het eerste voorbeeld een A exception wordt opgevangen door een B catch zou je verwachten dat dat hier dus ook gebeurd.
hier zal de catchhandler van A worden aangeroepen, ipv die van B (wat ik dus zo onlogisch vond ;))
Maar je zou dus verwachten dat als je de catch voor A weghaald, wel de catch voor B wordt aangeroepen? Anders zou het eerste voorbeeld erg maf zijn omdat daar de 'A' wel door een catch van B wordt opgevangen?

Misschien is dit een (vreemde) optimalisatie?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op maandag 10 juni 2002 01:06 schreef mbravenboer het volgende:

[..]

Hum..... dat is maf :o .
das niet zo maf, omdat er geen runtime type specification is :)
Volgens mij is dit niet compatible met de beschrijving in het boek van Stroustrup (14.3.2.1: Order of Handlers): daar staat namelijk dat de handlers op volgorde geprobeerd worden. Dat is hier dus niet het geval :( .
waarom niet?
Eerst de B-handler. Maar je hebt een A, dus das niet goed
Dan de A-handler. Je hebt een A, dus hopla :)
(zonder de A-handler krijg je een uncaught exception error)
Als in het eerste voorbeeld een A exception wordt opgevangen door een B catch zou je verwachten dat dat hier dus ook gebeurd.
nee want je gooit een B (let wel: zonder die te casten naar A), en dat mag ook, want ook afgeleiden van de types in de specificatie mogen gethrowed worden (er wordt dus niet impliciet gecast)
Maar je zou dus verwachten dat als je de catch voor A weghaald, wel de catch voor B wordt aangeroepen? Anders zou het eerste voorbeeld erg maf zijn omdat daar de 'A' wel door een catch van B wordt opgevangen?
Zoals ik al zei, je hebt daar geen A maar een B (en de compiler weet dat)
Misschien is dit een (vreemde) optimalisatie?
nope :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: nee want je gooit een B (let wel: zonder die te casten naar A)
Ik zie het liever als een cast naar A door de throws specificatie van de methode.

Stel je voor dat de methode ook een exception C kan gooien naast de B, wat echter ook een extentie van A is (de throws declaratie zal dan hetzelfde blijven).

Wat gebeurt er dan als je een B en een C catch hebt? Als dan 1 van de specifieke catches wordt aangeroepen (wat volgens mij zo is als ik Stroustrup lees, in ieder geval is dit zo in Java) betekent dat dat er at runtime naar het type wordt gekeken: at compile time kan je niet weten of het een B of een C exception is.
nope :)
Bekijk eerst maar eens wat er gebeurt als je ook een C gooit en deze ook opvangt :P .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
marcusk: Ik dacht ook dat het was zoals Soultaker zegt.
Nee, want het daadwerkelijke type is niet altijd bekend at compile time:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class A {
   public void doSomething() {

   }
}

class B extends A {
   public void doSomething() {

   }
}

class C extends A {
   public void doSomething() {

   }
}

public A getValue() {
  if(...) {
     return new B();
  } else {
     return new C();
  }
}

public void test() {
  A a = getValue();
  a.doSomething();
}

Welke doSomething moet nu worden aangeroepen? Dat kan je pas at runtime bekijken, waarvoor dus descriptors van de klassen moeten worden geraadpleegd. Dat is single-dispatch.
Dan wordt toch in het eerste geval f(A) en in het tweede geval f(B) aangeroepen?
Yepz.
Anders zou het visitor pattern een beetje nutteloos zijn lijkt me) :?
Nee, want bij het visitor pattern is het at compile time bekend dat het 2e argument van een visit aanroep van een bepaald specifiek type is. Op basis daarvan kan een visit methode aangeroepen worden. Het 1e argument is in feite de instantie van de visitor en daarop vindt dispatching at runtime plaats (indien nodig).
Dus er wordt niet at-runtime gekeken naar het type van x; dan zou immers f(B) aangeroepen worden.
Het single-dispatch versus double-dispatch verhaal gaat op voor invocaties op instantie-methoden: daarbij is er een impliciet 1e argument, wat de instantie is waarop de methode wordt aangeroepen. Daarop vindt at runtime dispatching plaats.

Als je een methode aanroept die geen onderdeel uitmaakt van een klasse wordt er denk ik helemaal niets gedispatched omdat er simpelweg geen omschrijving is van de beschikbare methoden die at runtime gecontroleerd kan worden.

M'n verhaal heeft dus alleen betrekking op instantie methoden :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Topicstarter
Op maandag 10 juni 2002 00:54 schreef .oisyn het volgende:
Maar goed, mijn antwoord blijft hetzelfde: namelijk dat je niet per se een A mag throwen maar ook een afgeleide van A, zo zit de exception specification nou eenmaal in elkaar
Ah, mijn spreekwoordelijke kwartje is zojuist gevallen :).

Ik zat de hele tijd in gedachten een soort A& te initialiseren, terwijl inderdaad afgeleide typen ook gewoon gegooid (en dus opgevangen) mogen worden.

Overigens ben ik inmiddels al niet meer van plan die exception specificaties te gebruiken; het lijkt niet meer te zijn dan een nare manier om iets wat eigenlijk documentatie is met een speciale syntax op te nemen in de code..

Verwijderd

Topicstarter
Op maandag 10 juni 2002 01:17 schreef mbravenboer het volgende:

[..]

Ik zie het liever als een cast naar A door de throws specificatie van de methode.
Er is geen (impliciete) cast naar A door de throw specificatie, die fout maakte ik ook (en is de bron van dit hele topic :) ).

[edit] Sterker nog: dit is precies waar de topictitel op doelt :). [/edit]

Afgeleide typen zijn gewoon volledig toegestaan en eigenlijk impliciet opgenomen in de throw specificatie.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Btw: het Visitor pattern is inderdaad volledig nutteloos als je multi-methods/double dispatch hebt. Het is in feit een work-around voor het gebrek aan double dispatch.

Zie Nice, die multi-methods heeft:
http://nice.sourceforge.net/

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op maandag 10 juni 2002 01:17 schreef mbravenboer het volgende:

[..]

Ik zie het liever als een cast naar A door de throws specificatie van de methode.
wat ik probeer duidelijk te maken is dat de throws specificatie niet verbiedt dat een afgeleide van een type dat in de specificatie staat gegooid mag worden

Als je dus een A daarin hebt staan dan mag je dus een A gooien, maar ook een B (en elke andere afgeleide van A). Dat is niet omdat een B ook een A is, maar dat is zo omdat dat zo bepaald is :)

ANSI C++ draft, punt 15.4.8:
8 If a class X is in the type-id-list of the exception-specification of
a function, that function is said to allow exception objects of class
X or any class publicly and unambiguously derived from X. Similarly,
if a pointer type Y* is in the type-id-list of the exception-specifi-
cation of a function, the function allows exceptions of type Y* or
that are pointers to any type publicly and unambiguously derived from
Y. Otherwise, a function only allows exceptions that have the same
type as the types specified in the type-id-list of its exception-spec-
ification.
Stel je voor dat de methode ook een exception C kan gooien naast de B, wat echter ook een extentie van A is (de throws declaratie zal dan hetzelfde blijven).

Wat gebeurt er dan als je een B en een C catch hebt? Als dan 1 van de specifieke catches wordt aangeroepen (wat volgens mij zo is als ik Stroustrup lees, in ieder geval is dit zo in Java) betekent dat dat er at runtime naar het type wordt gekeken: at compile time kan je niet weten of het een B of een C exception is.
dit begrijp ik niet helemaal... kom eens met een code-voorbeeld?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: dit begrijp ik niet helemaal... kom eens met een code-voorbeeld?
Ok, ff tikken (tik niet zo vaak C++ ;) ).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

java begrijp ik ook hoor :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: java begrijp ik ook hoor :)
Hum ja, maar daar werkt het dus zoals ik zeg... :o . Het gaat er vooral om hoe het in C++ werkt ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

dat begrijp ik, maar het gaat ook uiteindelijk om de C++ versie, en niet hoe het in java werkt :)

.edit: schiet eens op je tiept niet snel genoeg :P

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Op maandag 10 juni 2002 01:20 schreef mbravenboer het volgende:
Welke doSomething moet nu worden aangeroepen? Dat kan je pas at runtime bekijken, waarvoor dus descriptors van de klassen moeten worden geraadpleegd. Dat is single-dispatch.
Maar dat werkt met virtuele functies. Dat heeft er toch niets mee te maken?
[edit]Hmmz, of juist wel :)
Het single-dispatch versus double-dispatch verhaal gaat op voor invocaties op instantie-methoden: daarbij is er een impliciet 1e argument, wat de instantie is waarop de methode wordt aangeroepen. Daarop vindt at runtime dispatching plaats.
Aha, nu snap ik het al beter geloof ik :)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Shit, je hebt gelijk :( ;)

Zie hier mijn eerste voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
using namespace std;

struct A {};
struct B : A {};
struct C : A {};

void f () throw (A) {
  int i;
  cin >> i;

  if(i > 10) {
    throw B();
  } else {
    throw C();
  }
}

int main () {
  try {
    f();
  }
  catch (B) {
    cout << "B";
  }
  catch (C) {
    cout << "C";
  }
}

Dat werkt dus zoals ik dacht te omschrijven: hij vangt een B of een C op.

Maar dan dit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;

struct A {};
struct B : A {};
struct C : A {};

void f () throw (A) {
  int i;
  cin >> i;

  A a;
  if(i > 10) {
    a = B();
  } else {
    a = C();
  }

  throw a;
}

int main () {
  try {
    f();
  }
  catch (B) {
    cout << "B";
  }
  catch (C) {
    cout << "C";
  }
}

en dat werkt dus niet :'( .

Ik sprak duidelijk teveel vanuit de aanname dat het wel hetzelfde zou werken als in Java en dat is duidelijk erg gevaarlijk ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
marcusk: Maar dat werkt met virtuele functies. Dat heeft er toch niets mee te maken?
Nou ja, het was een vergelijking met het exception systeem (wat dus nogal een foute vergelijking is, zoals je in m'n C++ gebrabbel kunt zien :( ).
Hmmz, of juist wel :)
Los gezien van het exception verhaal is het wel boeiend en relevant ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Topicstarter
mbravenboer:

Als je in c++

A a;
a = B();

doet, wordt het tijdelijke B object gesliced en wordt alleen het A subobject gekopieerd, de rest van het B object gaat gewoon verloren. Probeer het nog eens met een pointer of reference. :)

Iets teveel gejava't ? ;)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op maandag 10 juni 2002 01:44 schreef mbravenboer het volgende:Ik sprak duidelijk teveel vanuit de aanname dat het wel hetzelfde zou werken als in Java en dat is duidelijk erg gevaarlijk
ik dacht idd ook dat het werkte zoals in Java... tot ik het probeerde :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Sneechy: Iets teveel gejava't ? ;)
:( . Hehe ;) . Bedankt voor de tip :o . Ik probeer het ff...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Op maandag 10 juni 2002 01:46 schreef mbravenboer het volgende:
Nou ja, het was een vergelijking met het exception systeem (wat dus nogal een foute vergelijking is, zoals je in m'n C++ gebrabbel kunt zien :( ).
Ik bedoelde dat (ik dacht dat) virtuele functies niets met *-dispatching te maken had. Maar ik begrijp nu dat dat juist wel het geval is? :)
Los gezien van het exception verhaal is het wel boeiend en relevant ;) .
Zeker :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

even weer terug naar single-dispatching :)
Op maandag 10 juni 2002 00:58 schreef mbravenboer het volgende:

Nee, bij single-dispatch wordt de moeite genomen om at runtime de omschrijving van de klassen te raadplegen om te bekijken welke methode er aangeroepen moet worden. Dit klinkt natuurlijk onwijs omslachtig, maar dat valt wel iets mee omdat het natuurlijk enorm geoptimaliseerd geimplementeerd wordt en bij veel methode aanroepen zelfs weg-geoptimaliseerd kan worden.
heeft java dan niet net als C++ gewoon virtual tables? of bedoel je dat ook bij het 'opzoeken van de omschrijving van een klasse'

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

trouwens ook wel interessant om te vermelden dat als je een excpetie doorgooit dat het type dan wel behouden blijft
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try
{
    try
    {
        throw new B ();
    }
    catch (A * a)
    {
        cout << "nested a" << endl;
        throw;
    }
    
}
catch (B * b)
{
    cout << "b" << endl;
}
catch (A * a)
{
    cout << "a" << endl;
}

de output hiervan zal zijn:
code:
1
2
nested a
b

Terwijl je een A * hebt in de geneste catch... maar die wordt dus niet gecast door de hergooi
verander je dat geneste stukje echter:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try
{
    try
    {
        throw new B ();
    }
    catch (A * a)
    {
        cout << "nested a" << endl;
        throw a; // <-- gooi a opnieuw
    }
    
}
catch (B * b)
{
    cout << "b" << endl;
}
catch (A * a)
{
    cout << "a" << endl;
}

dan zal de output zijn
code:
1
2
nested a
a

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik bedoelde dat (ik dacht dat) virtuele functies niets met *-dispatching te maken had. Maar ik begrijp nu dat dat juist wel het geval is?
Inderdaad, single-dispatching is wordt juist toegepast bij virtuele functies: het eerste argument (waarop dispateched wordt) is het object waarop de methode wordt aangeroepen.
.oisyn: heeft java dan niet net als C++ gewoon virtual tables? of bedoel je dat ook bij het 'opzoeken van de omschrijving van een klasse'
Jezeker, dat bedoelde ik inderdaad, maar trachte het in normale taal te omschrijven, wat duidelijk alleen maar verwarrend werkt ;) .

Java heeft ook gewoon virtual tables (althans, dat is niet gespecificeerd denk ik, maar goed) en gebruikt ook single-dispatch. Het voordeel van een virtual machine omgeving is wel dat er door de hotspot compiler analyse kan worden uitgevoerd en eventueel optimalisaties kunnen worden doorgevoerd bij methoden aanroepen (zie mijn laatste twee posts hier: [topic=517773] )

Zie ook de JVM en Java Lang spec:

Method area:
http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html#6656
invokevirtual:
http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html#31293
Method invocation expression:
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#20448

Het wordt in de laatste dynamic method lookup genoemd...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: trouwens ook wel interessant om te vermelden dat als je een excpetie doorgooit dat het type dan wel behouden blijft

Terwijl ...
Het moet niet veel gekker worden ;)

* mbravenboer moet nodig gaan pitten :o :O :z .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

mooi he, dat C++ ;)
* .oisyn gaat ook pitten, morgen tentamen toegepaste wiskunde (koekie :P)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
.oisyn: mooi he, dat C++ ;)
Je zou C# zowat meerwaarde gaan toedichten ;) .

(kidding: alle .NET fans, kom maar gelijk van de kast :P ).

Trusten :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • marcusk
  • Registratie: Februari 2001
  • Laatst online: 26-09-2023
Weltrusten :)

* marcusk gaat ook maar slapen dan ;)

Verwijderd

Topicstarter
En ik houd het ook maar weer voor gezien voor vandaag.. (morgen ASP tentamen >:) )

Verwijderd

Op maandag 10 juni 2002 02:32 schreef Sneechy het volgende:
En ik houd het ook maar weer voor gezien voor vandaag.. (morgen ASP tentamen >:) )
en t was een butt-tentamen :( :(

ik ga toch stroustrups boek er maar eens bijpakken als ik klaar ben met de tentamens :P

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

oe ik had tentamen toegepaste wiskunde

alleen ik kreeg m niet af omdat de polaire functie van mijn rekenmachine niet klopt :? Dus daardoor heb ik een half uur verknald ofzo :(

oh well, vast wel voldoende, en ik kan m altijd nog herkansen :)

trouwens, ga eens ontopic, het is de HK niet! :( ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 18:44
Op maandag 10 juni 2002 12:33 schreef .oisyn het volgende:
oe ik had tentamen toegepaste wiskunde

alleen ik kreeg m niet af omdat de polaire functie van mijn rekenmachine niet klopt :? Dus daardoor heb ik een half uur verknald ofzo :(

trouwens, ga eens ontopic, het is de HK niet! :( ;)
catch (invalid_argument) ;)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1