Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.
Toon posts:

[JAVA] Implementen van een Interface d.m.v. reflection?

Pagina: 1 2 Laatste
Acties:
  • 461 views sinds 30-01-2008
  • Reageer

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 14-11 21:45

voodooless

Sound is no voodoo!

Verwijderd schreef op 16 juni 2004 @ 19:54:
[...]

Ik wil iedereen aanraden om even goed te lezen wat ik allemaal zeg, want ik moet telkens in herhaling vallen (nofi).
Opgesomt:
- Ik 'ken' de Interface, dwz: haar classname en gewoon de volledige code (dus ook methods etc.)
- Echter, ik kan deze niet importen
- Ik weet dus heel goed welke methods ik dien te implementen, ik heb in feite een aparte klasse die volledig functioneel is op één ding na: het ontbreekt hem aan een "implements" keyword met daarachter de Interface-naam.
- Ik wil runtime aangeven dat die bewuste klasse die Interface moet implementen (ja, ik weet het, als je een method niet/onjuist implement is het "panic" in de VM aangezien je dit niet met de compiler kunt afvangen :o)
- Ik weet (natuurlijk, anders zou het wel onzinnig zijn) wel de naam van de Interface, en weet de .class file ook te vinden uiteraard.

Als ik die naam heb ben ik al een stuk verder ja... en dan?
Het is niet zozeer het goed lezen, maar meer het goed begrijpen wat je wil... Dat is nu al stukken duidelijker:)

Je hebt gewoon een klasse die een interface implementeerd, zonder dat er in de code een implements staat... toch?

Nu wil je run-time op de een of andere manier deze interface bij die classe frotten, zodat je deze via de interface kunt benaderen... ja?

Volgens mij kan dat idd bijna alleen alleen als je run-time bytecode gaat hacken. Andere truck: maak runtime een nieuw java bestand:

Java:
1
2
3
public class helpclasse extends jeClass implements jeInterface{
// verder leeg
}


Deze moet je dan runtime compileren en dan heb je een klasse die de interface implementeerd en de methodes heeft van de orginele klasse. Beetje een omweg, maar volgens mij moet dat kunnen.

Maar vaag: Wat is het probleem om bij de code van je classe erbij te zetten dat die die interface implemeteerd? Dan ben je toch gewoon van het gehele gezeur af!
offtopic:
Worden meer mensen tureluurs van mijn avatar onder FireFoix 0.9 ?
Yep :+

[ Voor 6% gewijzigd door voodooless op 16-06-2004 20:30 ]

Do diamonds shine on the dark side of the moon :?


Verwijderd

Topicstarter
Alarmnummer schreef op 16 juni 2004 @ 20:19:
[...]

Als jij een normale Java applicatie draait (bv een commandline tool) dan heeft ie volledige rechten zoals iedere andere applicatie.
Zie laatste edit. :P
[...]

Dat het in een interfaceloze taal sneller gebeurt dat je van meerdere clases moet extenden. Vooral omdat je ook nog een geen innerclasses hebt, dus ook niet op een andere (nette) manier bij de inhoud van een class kan komen.
Maar het feit dat een taal geen inner classes heeft is natuurlijk geen logisch gevolg van het feit dat hij interfaceloos is. ;)
Verder is dat extenden (van abstracte classes dan) de vervanger van Interfaces in Java dus het maakt weinig uit of je er wel of niet onderuit komt toch? :P
[...]

Hoeveel ervaring heb jij eigelijk met programmeren/programmeren in Java? Delagates zijn een ware uitkomst doordat je op kleine subtaken kunt concentreren en een afgezand(delegate) de deur uit kunt doen om die taak af te handelen. Dus ipv dat een class alles zelf moet oplossen (waardoor hij meerdere clases moet extenden) kan hij dit overlaten aan zo`n delegate. Het geeft een heel licht, inzichtelijk ontwerp.
Niet echt veel, ik doe uit mezelf ervaring op en leer zaken op het moment dat het mij uitkomt. Maar ik heb er wel aardig inzicht in hoor, om even onbescheiden te doen. :P
Erg lui etc., maar aan het voorkauwen van stof zoals ze op je studie doen heb je vrij weinig.

Dat kan ook met delegates in een aparte (en niet inner) class. Gewoon een Vector (of ArrayList, Hashmap, enz. ;)) vullen met deze delegates en die zaken waar toegang tot zou moeten zijn doorgeven via een soort van inter-class communication.
Ja ik weet het, dat is weer onnodig traag/complex/noem maar op, maar zo zou ik zoiets standaard aanpakken. :+

  • Bobco
  • Registratie: Januari 2001
  • Laatst online: 30-10-2023

Bobco

I used to dream about Verona.

Verwijderd schreef op 16 juni 2004 @ 20:08:
[...]

Maar daar betrap ik je wel op een denkfout. Ik zeg niet dat ik byte-code wil (kunnen) manipuleren, ik zeg iets te willen waarvan jij zegt dat dat op dit moment alleen op deze wijze kan. Dat is natuurlijk iets heel anders, mij hoor je ook niet ontkennen dat je alleen in uiterste gevallen op dit soort methodieken moet terugvallen, zoals ik eerder ook al beaam.
Ik blijf dit een nogal kunstmatig probleem vinden. Je wilt je applicatie laten werken met classes die je at compile time niet kent, maar waarvan je wel verwacht dat ze een bepaalde interface implementeren, alhoewel dat niet expliciet is aangegeven met een implements.

Het lijkt me dat er stapels applicaties zijn die op deze manier classes aanroepen en gebruiken, servlets zijn er een simpel voorbeeld van. Als je dynamisch wilt kunnen bepalen welke interface van toepassing is op een bepaalde class ontkom je niet aan reflection en/of byte-code manipulatie.

Maar ondanks dat jij hardnekkig blijft weigeren om te vertellen waar dit nu allemaal om begonnen is ben ik toch wel heel nieuwsgierig naar de toepassing die jij in gedachten hebt...

With the light in our eyes, it's hard to see.


Verwijderd

Topicstarter
deepspace schreef op 16 juni 2004 @ 20:28:
[...]


Het is niet zozeer het goed lezen, maar meer het goed begrijpen wat je wil... Dat is nu al stukken duidelijker:)
Dat begrip zou moeten volgen uit het zorgvuldig lezen van het topic. >:)
Je hebt gewoon een klasse die een interface implementeerd, zonder dat er in de code een implements staat... toch?
Dat zou ik graag willen ja.
Nu wil je run-time op de een of andere manier deze interface bij die classe frotten, zodat je deze via de interface kunt benaderen... ja?
Ja. Maar ik wil niets via die Interface benaderen, die Interface genereert gewoon zelfstandig events (zal wel niet goed verwoord zijn ivm Listener/Adapters maar you get the point hoop ik ;))
Volgens mij kan dat idd bijna alleen alleen als je run-time bytecode gaat hacken. Andere truck: maak runtime een nieuw java bestand:

Java:
1
2
3
public class helpclasse extends jeClass implements jeInterface{
// verder leeg
}


Deze moet je dan runtime compileren en dan heb je een klasse die de interface implementeerd en de methodes heeft van de orginele klasse. Beetje een omweg, maar volgens mij moet dat kunnen.
(Hier spreekt de JVM):
<java: Welke Interface bedoelt u, meneer deepspace?>
Maar vaag: Wat is het probleem om bij de code van je classe erbij te zetten dat die die interface implemeteerd? Dan ben je toch gewoon van het gehele gezeur af!
OMG :D
Probleem is al opgelost!! :X
Nu kunnen we toch heerlijk verder discussieren over het hoe & waarom rond dit (theorethische) probleem? :9

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 16 juni 2004 @ 20:30:
Maar het feit dat een taal geen inner classes heeft is natuurlijk geen logisch gevolg van het feit dat hij interfaceloos is. ;)
Ja en?
Verder is dat extenden (van abstracte classes dan) de vervanger van Interfaces in Java
Bij een abstracte class kan je niet garanderen dat er geen implementaties/velden aanwezig zijn en bij een interface wel. Een interface is dus een sterke eis dan een abstracte class.
dus het maakt weinig uit of je er wel of niet onderuit komt toch? :P
Developen is niet een kwestie van ergens onder uit komen maar een goeie oplossing te bedenken voor een probleem. En de snelste oplossing is niet altijd de beste oplossing, omdat een groot deel van de tijd ook code onderhouden moet worden en niet van die schoolvoorbeeldjes zijn die je daarna weg kan flikkeren. Dus eisen als onderhoudbaarheid zijn gewoon een must voor software als het kans van slagen wil hebben. Zoek anders even naar: stove pipe systems.
Niet echt veel, ik doe uit mezelf ervaring op en leer zaken op het moment dat het mij uitkomt. Maar ik heb er wel aardig inzicht in hoor, om even onbescheiden te doen. :P
Zoals bobco al zei, je hebt een enorm kunstmatig probleem die eigelijk ook niet bijster interessant is om op te lossen.
Dat kan ook met delegates in een aparte (en niet inner) class. Gewoon een Vector (of ArrayList, Hashmap, enz. ;)) vullen met deze delegates en die zaken waar toegang tot zou moeten zijn doorgeven via een soort van inter-class communication.
Doe dan niet zo ingewikkeld en maak alle velden dan lekker public.

[ Voor 4% gewijzigd door Alarmnummer op 16-06-2004 20:40 ]


Verwijderd

Topicstarter
Bobco schreef op 16 juni 2004 @ 20:32:
[...]
[...]
Daarom was het ook opgelost. :D :'( :D

[]Je wilt je applicatie laten werken met classes die je at compile time niet kent, maar waarvan je wel verwacht dat ze een bepaalde interface implementeren, alhoewel dat niet expliciet is aangegeven met een implements.
Juist. Is zo gek toch niet, in theorie?
Het lijkt me dat er stapels applicaties zijn die op deze manier classes aanroepen en gebruiken, servlets zijn er een simpel voorbeeld van. Als je dynamisch wilt kunnen bepalen welke interface van toepassing is op een bepaalde class ontkom je niet aan reflection en/of byte-code manipulatie.
Reflection lijkt me ook ja, maar byte-code manipulatie vind ik een te zwaar (en lelijk) middel. Via byte-code manipulatie kan je wel meer... maar of dat zo wenselijk is?
Maar ondanks dat jij hardnekkig blijft weigeren om te vertellen waar dit nu allemaal om begonnen is ben ik toch wel heel nieuwsgierig naar de toepassing die jij in gedachten hebt...
Als ik dit al zou willen zouden mijn projectleden dit niet echt op prijs stellen.
Maar een simpel voorbeeld is wat ik al zei in het begin, als je libraries niet import maar dynamisch load, en je gebruikt ergens een nogal netelige Interface-constructie zal je dit weldra tegenkomen denk ik...

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 16 juni 2004 @ 20:43:
[...]
Als ik dit al zou willen zouden mijn projectleden dit niet echt op prijs stellen.
Maar een simpel voorbeeld is wat ik al zei in het begin, als je libraries niet import maar dynamisch load, en je gebruikt ergens een nogal netelige Interface-constructie zal je dit weldra tegenkomen denk ik...
Ok tip: als je met crap constructies bezig moet... dan is de kans redelijk groot dat je ontwerp dus gewoon zuigt.

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 14-11 21:45

voodooless

Sound is no voodoo!

Verwijderd schreef op 16 juni 2004 @ 20:38:
Dat begrip zou moeten volgen uit het zorgvuldig lezen van het topic. >:)
Dat zie ik dus absoluut niet zo. Ik ben immers niet de enigste die het niet duidelijk vond. Met iedere letter drie keer uitpluizen wordt het er echt niet beter op.
Ja. Maar ik wil niets via die Interface benaderen, die Interface genereert gewoon zelfstandig events (zal wel niet goed verwoord zijn ivm Listener/Adapters maar you get the point hoop ik ;))
Dat maakt toch niet uit. Je zult die die interface (implementatie) instantie (zo zal ik het maar ff noemen), toch wel moeten zeggen waar hij z'n ei kwijt kan. Die events moeten immers ergens heen gaan.
(Hier spreekt de JVM):
<java: Welke Interface bedoelt u, meneer deepspace?>
Hoezo welke interface... Je zegt net zelf:
- Ik 'ken' de Interface, dwz: haar classname en gewoon de volledige code (dus ook methods etc.)
Je kent de classname en code, dus kun je die ook in een run-time gegenereede java file dumpen...
OMG :D
Probleem is al opgelost!! :X
Nu kunnen we toch heerlijk verder discussieren over het hoe & waarom rond dit (theorethische) probleem? :9
Bij deze dan... :+

Do diamonds shine on the dark side of the moon :?


Verwijderd

Topicstarter
Nou dat! :D
Je impliceerde het tegendeel. ;)
[...]

Bij een abstracte class kan je niet garanderen dat er geen implementaties/velden aanwezig zijn en bij een interface wel. Een interface is dus een sterke eis dan een abstracte class.
Bedoel je geen velden anders dan die in de Interface zelf gedefineerd worden?
Ja, dat is waar. Hebben ze daar bij C++ dan niks op gevonden? :?
[...]

Developen is niet een kwestie van ergens onder uit komen maar een goeie oplossing te bedenken voor een probleem. En de snelste oplossing is niet altijd de beste oplossing, omdat een groot deel van de tijd ook code onderhouden moet worden en niet van die schoolvoorbeeldjes zijn die je daarna weg kan flikkeren. Dus eisen als onderhoudbaarheid zijn gewoon een must voor software als het kans van slagen wil hebben. Zoek anders even naar: stove pipe systems.
Heb je volledig gelijk in, is ook niet in tegenspraak met wat ik zeg. Maar we gaan wel weer offtopic. :o
[...]

Zoals bobco al zei, je hebt een enorm kunstmatig probleem die eigelijk ook niet bijster interessant is om op te lossen.
Voor mij is het interessant genoeg. Ik wil gewoon weten of het kan ja/nee. Zo nee, dan weet ik dat en daar denk ik dan het mijne van. :)
[...]

Doe dan niet zo ingewikkeld en maak alle velden dan lekker public.
Ik zei zelf idd al dat het ingewikkeld is. ;(
Maar public is wél veel krakkemikkiger/lelijker...

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 16 juni 2004 @ 20:51:
[...]
Bedoel je geen velden anders dan die in de Interface zelf gedefineerd worden?
Ja, dat is waar. Hebben ze daar bij C++ dan niks op gevonden? :?
Puur virtuele classes (dus interfaces) bestaan niet bij c++. Je kan het tenminste niet compiletechnisch afdwingen.
Maar public is wél veel krakkemikkiger/lelijker...
Lood om oud ijzer. Het zijn gewoon kutoplossingen.

Verwijderd

Topicstarter
Alarmnummer schreef op 16 juni 2004 @ 20:46:
[...]

Ok tip: als je met crap constructies bezig moet... dan is de kans redelijk groot dat je ontwerp dus gewoon zuigt.
Hehe...
Wat was ook al weer de status van dit probleem.... ?
:D

Design gewijzigd, opgelost! :D ;( :D

Maar als dit zonder poespas zou kunnen (bijv. dmv van de reflection API) is het geen crap-constructie natuurlijk.

Verwijderd

Topicstarter
deepspace schreef op 16 juni 2004 @ 20:48:
[...]


Dat zie ik dus absoluut niet zo. Ik ben immers niet de enigste die het niet duidelijk vond. Met iedere letter drie keer uitpluizen wordt het er echt niet beter op.
Nou ik heb het duidelijk gezegd in de start post en een eindje verder, toen bij een ander ook het kwartje viel, heb ik het nog eens herhaald...
[...]


Dat maakt toch niet uit. Je zult die die interface (implementatie) instantie (zo zal ik het maar ff noemen), toch wel moeten zeggen waar hij z'n ei kwijt kan. Die events moeten immers ergens heen gaan.
Precies, en hoe doe ik dat run-time?
[...]


Hoezo welke interface... Je zegt net zelf:

[...]

Je kent de classname en code, dus kun je die ook in een run-time gegenereede java file dumpen...
Dat is een vergelijkbare oplossing als byte-code manipulatie...
Maar is op zich wel een idee, want dmv de reflection API kun je wel dynamisch een Class-object opbouwen, zou er ook een voorziening zijn voor het implements-keyword? (8>

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 16 juni 2004 @ 20:54:
Maar als dit zonder poespas zou kunnen (bijv. dmv van de reflection API) is het geen crap-constructie natuurlijk.
Reflection is in 99% van de gevallen ook een crap oplossing. Je kan compiletime geen garanties geven (pas runtime). En we zijn in de it altijd zo blij als de compiler ons al zoveel mogelijk kan wijzen op fouten ipv dat je het runtime tegenkomt (misschien.. misschien niet.. misschien wel dat na 10 week de buggy code geexecute wordt).

Advies: leer ontwerpen, leer patterns.

[ Voor 5% gewijzigd door Alarmnummer op 16-06-2004 20:59 ]


Verwijderd

Topicstarter
Alarmnummer schreef op 16 juni 2004 @ 20:54:
[...]

Puur virtuele classes (dus interfaces) bestaan niet bij c++. Je kan het tenminste niet compiletechnisch afdwingen.
C++'s bad. :)
[...]

Lood om oud ijzer. Het zijn gewoon kutoplossingen.
Precies, is de goede wel mogelijk?

[ Voor 3% gewijzigd door Verwijderd op 16-06-2004 20:59 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 16 juni 2004 @ 20:59:
Precies, is de goede wel mogelijk?
Een delegate is een goeie oplossing.

Verwijderd

Topicstarter
Alarmnummer schreef op 16 juni 2004 @ 20:58:
[...]

Reflection is in 99% van de gevallen ook een crap oplossing. Je kan compiletime geen garanties geven (pas runtime). En we zijn in de it altijd zo blij als de compiler ons al zoveel mogelijk kan wijzen op fouten ipv dat je het runtime tegenkomt (misschien.. misschien niet.. misschien wel dat na 10 week de buggy code geexecute wordt).

Advies: leer ontwerpen, leer patterns.
Dat maakt het nog geen crap-oplossing...
Als je goed test is het theoretisch gezien net zo solide code...
Maar idd, het is wel een praktische keerzijde.

Ontwerpen en patterns doe/ken ik al waar nodig, verder is het geen professionele toepassing dus ik pak het ook niet zo aan, het is alleen maar om wat te leren. Als je alles meteen goed doet kom je in moeilijke gevallen later in de problemen. :)

Verwijderd

Topicstarter
Alarmnummer schreef op 16 juni 2004 @ 21:01:
[...]

Een delegate is een goeie oplossing.
Oplossing wel, maar het blijft een logisch <-> semantisch gedrocht. :+
Maar ja, dat is wellicht inherent aan Java. :P

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

even nogmaals een vriendelijk verzoek om een en ander helder, ontopic en vriendelijk te houden dank u ;)

Cybarite: ben je niet toevallig op zoek naar een Java-variant van de (D)COM-interface IDispatch? Zo nee sluit ik me aan bij de rest van de profs hier die geen bal van je probleem snapt ;)

Professionele website nodig?


Verwijderd

Topicstarter
Volgens mij is alles aardig vriendelijk, meer zelfs dan je zou verwachten op GoT in dit soort topics... :P

Ik kan niet zeggen of ik op zoek ben naar IDispatch, aangezien ik dat niet ken (zal wel C++ zijn oid).

Verder heb ik nu al een paar keer gezegd dat het 'probleem' is opgelost. Dat wil zeggen er valt niets aan te begrijpen. Dan kunnen we nu (ontopic ;)) verder gaan met de discussie achter het hoe en waarom, als dit tenminste echt niet zou kunnen (die laatste suggestie van deepspace lijkt me nog het beste).

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 14-11 21:45

voodooless

Sound is no voodoo!

Ik vind het eigenlijk ook wel redelijk vriendelijk..

Om maar ff in te haken op mijn oplossing:

Wat je dus eigenlijk moet doen is zelf een classe maken en de java compiler aanroepen. Ik heb hier een stukje gevonden over hoe dat zou kunnen:

http://www.javaworld.com/javatips/jw-javatip131.html

Do diamonds shine on the dark side of the moon :?


Verwijderd

Topicstarter
Dat is idd hoe je het kunt doen. Echter wel tamelijk 'dirty'... :D

Maar goed, ik heb gezien dat je al dynamisch een class kunt opbouwen met de reflection API dus ik zal dat als ik tijd heb (= iig ná dit weekend :o) eens uitzoeken. Code zal ik posten natuurlijk. Is weldegelijk interessant hoor. :D

[ Voor 3% gewijzigd door Verwijderd op 16-06-2004 22:36 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Verwijderd schreef op 16 juni 2004 @ 22:22:
Volgens mij is alles aardig vriendelijk, meer zelfs dan je zou verwachten op GoT in dit soort topics... :P

Ik kan niet zeggen of ik op zoek ben naar IDispatch, aangezien ik dat niet ken (zal wel C++ zijn oid).
Uhhhh, [google=IDispatch] en de eerste link klikken is toch niet zoveel moeite? :?

Professionele website nodig?


Verwijderd

Topicstarter
curry684 schreef op 16 juni 2004 @ 23:22:
[...]

Uhhhh, [google=IDispatch] en de eerste link klikken is toch niet zoveel moeite? :?
Nee, maar wel offtopic. :)

Wat ik daar zie is een equivalent van de Java reflection API, en ik zie daardoor niks over interfaces of virtual classes die je dynamisch kan laten implementen....

Het kan zijn dat ik wat over het hoofd zie, maar ik heb dus geen zin afgerekend te worden op mijn uitspraken over MFC (:?), dus daarom liet ik me er niet over uit.

[ Voor 5% gewijzigd door Verwijderd op 16-06-2004 23:58 ]


Verwijderd

Alarmnummer schreef op 16 juni 2004 @ 20:08:

(ik geloof dat c++ geen innerclasses heeft).
Dat heeft ie wel zeker, zelfs C had dat al. Het heet overigens wel anders: Nested ipv Inner. Je gebruikt het bv ook wel met enums, of unions.

Wel werkt het iets anders. Er wordt bij C++ niet impliciet de this pointer van de outer class meegegeven. Je kunt alleen statics van de outer class benaderen. In principe is Java op dit punt dus wat 'sterker'.

Ter leering ende vermaeck, rechtstreeks uit de MSDN documentatie:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
int x;
class enclose {
public:
   int x;
   static int s;
   class inner {
      void f() {
         x = 1;      // C2327; enclose::x is not static
         s = 1;      // ok; enclose::s is static
         ::x = 1;    // ok; ::x refers to global
      }
   };
};

Verwijderd

Topicstarter
Het heet overigens wel anders: Nested ipv Inner.
:+ What's in a name... :D

Java kan ook alleen de statics (?en/of finals?) benaderen van de outer class, als het in een this-context gebeurt.

Maar nu ontopic mensen. :)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Verwijderd schreef op 16 juni 2004 @ 23:56:
[...]

Nee, maar wel offtopic. :)

Wat ik daar zie is een equivalent van de Java reflection API, en ik zie daardoor niks over interfaces of virtual classes die je dynamisch kan laten implementen....

Het kan zijn dat ik wat over het hoofd zie, maar ik heb dus geen zin afgerekend te worden op mijn uitspraken over MFC (:?), dus daarom liet ik me er niet over uit.
Tis (D)COM, en IDispatch is de geeigende manier om aan een implementer die de feitelijke interface niet kent (die hoeft dus op compiletime nog niet te bestaan!!!) duidelijk te maken welke methods er zijn en welke parameters die nodig hebben. Deze methods kun je vervolgens via IDispatch::Invoke aanroepen zonder ooit een interface te hebben gezien.

Kan aan mij liggen, maar da's exact wat je wil zonder extreem ranzige bytecode trucs.

Professionele website nodig?


Verwijderd

Verwijderd schreef op 16 juni 2004 @ 23:56:
[...]

Wat ik daar zie is een equivalent van de Java reflection API, en ik zie daardoor niks over interfaces of virtual classes die je dynamisch kan laten implementen....
Als ik deze thread zo lees, dan begrijp ik het volgende:

(theoretisch) heb je:

A) Een classe X die je dynamisch laadt
B) Een interface Y waarvan je -weet- dat die volledig geimplementeerd wordt door de classe X
C) De compiler weet niet dat X eigenlijk ook een Y kan zijn, omdat je dit niet aangaf in de classe definitie.

Wat jij dus volgens mij zoekt is conceptueel simpel en lijkt enigsinds op de reinterpret_cast van C++. Hiermee zeg je tegen de compiler: Beschouw dit object voortaan als een [willekeurig class type].

In dit geval ligt de gehele verandwoordelijkheid dat de memory layout van het object klopt in jouw handen. 99% van de gevallen is reinterpret_cast een design fout, maar voor die 1% van de gevallen dat je uitgekiende low-level code schrijft kun je het gebruiken.

Wat C++ dan weer niet support is een dynamische naam van je target type. Echter, na dat je gecast hebt zul je toch iets willen doen met je object, bv aan een andere functie geven die een object van een bepaald type verwacht. In de praktijk zul je dus of de naam van je target type at compile weten in de code die de dynamisch geladen class gebruikt of je wilt wat anders doen met je object, maar dan heb je die reinterpret_cast niet nodig.

Bv, het volgende stukje laat zien dat je wel 2 compleet ongerelateerde classes naar elkaar kunt casten (hoewel dit echt slecht is in de praktijk), maardat je niet naar een type kunt casten waarbij het target type onbekend is:

C++:
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
33
34
35
36
template <typename T, typename S>
T dynamic_reinterpret_cast(S sourceType, T targetType) {
    return reinterpret_cast<T>(sourceType);
}

class Foo {
    public: void test() {
        std::cout << "In Foo" << std::endl;
    }
};

class BarBase {

    public: void test() {
        std::cout << "In Barbase" << std::endl;
    }

};

class Bar : public BarBase {
    public: void test() {
        std::cout << "In Bar" << std::endl;
    }
};

int main () { 

    BarBase* bar = new Bar; // dynamically obtained from 'somewhere'    

    Foo* foo = new Foo;

    // object treated as BarBase*, and (logically) not as a Bar*
    dynamic_reinterpret_cast(foo,bar)->test();

    return 0;
}


De 'domme' template die je in bovenstaande code ziet is dus overbodig en je kunt in dit geval de normale reinterpret_cast gebruiken.

edit: het bovenstaande voorbeeld werkt overigens ook als alle classes bv een member variable int a; hadden, je een waarde geeft aan a terwijl het object een Foo is, en dan vervolgens gebruikt als aan Bar:

C++:
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
class Foo {
    public: int a;
    public: void test() {
        std::cout << "In Foo a=" << a << std::endl;
    }
};

class Bar {
    public: int a;
    public: void test() {
        std::cout << "In Bar a=" << a << std::endl;
    }
};

int main () { 

    
    Foo* foo = new Foo;
    foo->a = 4;

    Bar* bar = reinterpret_cast<Bar*>(foo);
    
    bar->test(); // prints: In Bar a=4

    return 0;
}


Wat ik overigens nog niet heb gelezen (of mischien las ik overheen), wat gebeurt er precies met het dynamisch geladen object nadat ie 'de interface heeft gekregen'?

Is het de bedoeling dat het object aan een functie wordt doorgegeven die een object van het type van de interface verwacht of iets anders? In het geval van het eerste, is het type van de argumenten van deze functie bekend op de plek waar je de code gebruikt?

Dus bv:

code:
1
2
3
4
5
6
7
Object X = dynamisch geladen object;

Object Y = dynamisch geladen object;

Type T = Type van eerste argument van functie set() van X

Execute functie set( reinterpret_cast<T> (Y) ) van X;


Zoiets?

[ Voor 28% gewijzigd door Verwijderd op 17-06-2004 01:53 ]


Verwijderd

Topicstarter
curry684 schreef op 17 juni 2004 @ 01:25:
[...]

Tis (D)COM, en IDispatch is de geeigende manier om aan een implementer die de feitelijke interface niet kent (die hoeft dus op compiletime nog niet te bestaan!!!) duidelijk te maken welke methods er zijn en welke parameters die nodig hebben. Deze methods kun je vervolgens via IDispatch::Invoke aanroepen zonder ooit een interface te hebben gezien.

Kan aan mij liggen, maar da's exact wat je wil zonder extreem ranzige bytecode trucs.
Dat is heel mooi, en daar blijkt dan pijnlijk uit:
dit is een gebrek in Java t.o.v. alternatieven (was het nou MFC? C#?).

Zo gek is mijn suggestie dus niet eens, zelfs MS heeft de moeite gedaan om dit mogelijk te maken. O-)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Verwijderd schreef op 17 juni 2004 @ 01:35:
[...]

Dat is heel mooi, en daar blijkt dan pijnlijk uit:
dit is een gebrek in Java t.o.v. alternatieven (was het nou MFC? C#?).\
Ik zei al dat het (D)COM was, wat door VB, Java (!), C++, .NET en weet ik het wat gebruikt kan worden. Het ging me echter enkel om het principe, dit kun je in Java namelijk ook implementeren.

Echter, het is namelijk wederom een ranzige workaround om iets dat je in OOP gewoon niet moet willen: service without contract. Maar minder ranzig dan bytecode alteration.

In .NET is dit gelukkig stukken netter opgelost, daar wordt alles via SOAP gedaan, waardoor je alsnog een contract hebt met native interfacing.
Zo gek is mijn suggestie dus niet eens, zelfs MS heeft de moeite gedaan om dit mogelijk te maken. O-)
COM in het algemeen wordt dan ook door de hele wereld (incluis Microsoft) gezien als Microsoft's stomste fout ooit.

Professionele website nodig?


  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 99% gewijzigd door Eelis op 18-02-2015 19:27 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Eelis schreef op 17 juni 2004 @ 04:05:
[...]


[...]

Waarom zou je dat willen afdwingen?
Om een contract te definieren waar een class moet aan voldoen, zonder dat daar implementatie aan tepas komt.
Zie ook dit topic:
[rml][ java] klasse interface[/rml]

[ Voor 10% gewijzigd door whoami op 17-06-2004 08:38 ]

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat legt niets uit, dat veranderd de vraag alleen maar :)
whoami schreef op 17 juni 2004 @ 08:37:
zonder dat daar implementatie aan tepas komt.
Waarom zou je dat willen afdwingen? :)

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.


  • vinnux
  • Registratie: Maart 2001
  • Niet online
Verwijderd schreef op 16 juni 2004 @ 20:00:
Ik vind het ook onzin dat bijv. multiple inheritance niet in Java is opgenomen. De genoemde "schaduwzijden" zijn stuk voor stuk te voorkomen als de programmeur fatsoenlijk kijkt wat hij doet (bijv. geen meerdere klassen maken met dezelfde methods, en een andere class van al deze classes de methods laten inheriten 8)7).
Als de programmeur "goed" zou programeren was er helemaal geen behoeft aan 3de generatie talen etc. Maar er is gebleken dat een 2de generatie programma niet te beheren is boven een bepaald aantal regels. Door telkens de touwtjes van een nieuwe generatie taal aan te trekken en de programmeur te dwingen om bepaalde dingen op één manier op te lossen wordt je code onderhoudbaarder.

Programeurs maken nu eenmaal fouten en op deze manier voorkom je dat op een lager niveau.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Met een abstracte class ben je nooit zeker dat er geen implementatie bij komt kijken.

Als je verschillende objecten hebt, waarvoor je een bepaald 'contract' wilt specifiëren, kan het handig zijn dat je zeker weet dat er geen andere logica komt bij kijken.

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

whoami schreef op 17 juni 2004 @ 13:36:
Met een abstracte class ben je nooit zeker dat er geen implementatie bij komt kijken.
Dat weet je wel zeker, want je bent zelf de ontwerper van de interface. Het is niet zo dat de gebruiker van een interface ineens members en implementaties kan gaan toevoegen ofzo. Degene die een "interface" ontwerpt heeft zelf de keuze hoe hij die klasse in elkaar zet. In C++ is dat dus een klasse met alleen maar pure virtual methods. Daar zit geen implementatie in, en dat weet je ook zeker omdat je zelf de ontwerper bent van die interface. Ik vind het dus een non-argument :).

Je zegt dus eigenlijk dat je wilt dat er wat syntactische suiker toe wordt gevoegd: introduceer een interface keyword, die ervoor zorgt dat alle members pure virtual zijn. Verder compilet het gewoon als iedere andere class. Dat vind ik eerlijk gezegd een beetje onzin eigenlijk :)

[ Voor 18% gewijzigd door .oisyn op 17-06-2004 13:44 ]

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.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
.oisyn schreef op 17 juni 2004 @ 13:39:
[...]


Dat weet je wel zeker, want je bent zelf de ontwerper van de interface.
Niet als ik een framework heb geschreven, en jij dat framework gebruikt.

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

:?
Als jij een framework hebt geschreven, dan heb jij toch ook de interfaces ontworpen? Dan weet je toch zeker dat in de interface zelf geen implementatie zit?

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.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Ja, maar als jij dat framework gebruikt, dan weet jij niet zeker of ik in de abstracte classes die ik in dat framework gestoken heb er geen implementatie in zit.

ik .... jij ... staat er in m'n vorige post

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik snapte wel wat je bedoelde, maar mijn punt is dat jij dan een fout ontwerp gemaakt hebt. Dat kan met Java en .Net net zo goed, door abstracte classes te gebruiken ipv interfaces, dan zit je met hetzelfde probleem. Door het gemis van MI is die fout in Java en .Net natuurlijk wel veel problematischer dan in C++, maar de fout is in essentie hetzelfde. Je kunt een compiler wel af laten dwingen dat een interface geen implementatie mag hebben, maar wat weerhoud jou ervan om een class te gebruiken ipv een interface? Analoog daaraan: wat weerhoud jou ervan om een implementatie toe te voegen aan een interface in C++? In beide gevallen heb je het gewoon niet begrepen en heb je een fout ontwerp geproduceerd.

Trouwens
dan weet jij niet zeker of ik in de abstracte classes die ik in dat framework gestoken heb er geen implementatie in zit
Dat weet ik wel zeker, dat kan ik namelijk in de header zien. Als alle members pure virtual zijn dan kan ik aannemen dat er geen implementatie is. (In werkelijkheid kan die implementatie er overigens wel zijn, maar dan moet ik die expliciet aan gaan roepen, en aangezien ik al aangenomen had dat die er niet was omdat alles pure virtual was, ga ik die dus ook niet aanroepen. De implementatie heeft dan dus ook niet echt veel nut)

[ Voor 34% gewijzigd door .oisyn op 17-06-2004 14:29 ]

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.


Verwijderd

.oisyn schreef op 17 juni 2004 @ 13:45:
:?
Als jij een framework hebt geschreven, dan heb jij toch ook de interfaces ontworpen? Dan weet je toch zeker dat in de interface zelf geen implementatie zit?
Volgens mij zitten Alarmnummer en whoami er toch wel een 'beetje' naast. Ik ben het dan ook meer met .oisyn eens in deze kwestie, alhoewel voor allebij de standpunten wel iets valt te zeggen.

Aan de ene kant klinken Alarmnummer en whoami overtuigend: Je kunt bij het aangeven dat een class een interface implementeerd in C++ niet aangeven dat het perse een interface moet zijn. Iemand kan dus 'stiekum' ipv de puur abstracte base class jouw class van een base laten inheritten die wel implementatie heeft.

Maar...

Als jij de ontwerper bent dan bepaal jij of dat gebeurt. Met de interfaces in Java heb je een zelfde soort probleem: iemand kan net zo goed 'stiekum' een methode weghalen in de definitie van de interface die jij implementeerd. Waarom is dit zoveel verschillend dan wanneer iemand in C++ 'stiekum' een implementatie toevoegt aan wat eerst een pure abstracte base was?

De bottomline is: Jij ontwikkeld de class, en daarbij ga je uit van bepaalde eigenschappen van de base. Als iemand jou class met een andere base gaat linken dan die jij bedoelde dan is er geen garantie dat alles nog goed gaat.

Java is dan mischien wel iets veiliger dan C++. Als de interface niet meer klopt compiled de code niet. In C++ zou een onbedoelde 'interface' verandering onopgemerkt kunnen gaan (omdat nu logica van de 'interface' kan worden uitgevoerd ipv de logica in de sub class). Echter, bij de gewone inheritance in Java zit je met precies hetzelfde probleem.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Met die abstracte class ben je nooit zeker dat er geen implementatie in de abstracte class zit. In sommige gevallen wil je dat nl. niet.

Een interface maak je, als je aan vele verschillende classes een bepaald 'contract' wilt toekennen.
Neem bv. de IList interface in .NET. Met die interface leg je een contract vast waar collection-classes moeten aan voldoen. Er zijn verschillende classes die die interface implementeren (ArrayList, DataView, ListItemCollection, .... ). Die classes hebben allemaal een andere implementatie, maar het zijn wel allemaal collecties.


Daarbij komt dan, dat bepaalde controls in .NET een property DataSource hebben, en die DataSource verwacht een object dat de IList implementeert. Hoe die methods precies geimplementeerd zijn, zal die control een worst wezen.

Wat zou het nut geweest zijn om daar een abstracte class te gebruiken ipv een interface ? Mocht daar een abstract class gebruikt zijn, dan zou dat ontwerp imo verkeerd geweest zijn.

Jij laat nu uitschijnen dat interfaces eigenlijk onnodig zijn. :?

https://fgheysels.github.io/


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Een interface maakt het onmogelijk dat er velden/methodeimplementaties worden toegevoegd en dat is dus een groot verschil met een class. Dus puur door het feit dat je werkt met een interface als basis kan je dus onmogelijk implementaties/velden toe gaan voegen en kan je je ook niet zo snel laten verleiden om snel ff een veldje toe te voegen.

Een interface is dus een hulpmiddel voor een programmeur om een beter ontwerp te krijgen. In principe als een c++ programmeur zich echt heel strak houd aan een puur virtuele class en zich nooit laat verleiden om even een veld/implementatie toe te voegen, dan is er idd geen verschil tussen een interface en zo`n virtuele class. Het probleem is dat dit vaak wel gebeurt (in ieder geval wel met java en abstracte classes). Hierdoor zijn ineens een hele lading patterns niet meer van toepassing.

Maar het wil niet zeggen dat je dan overal maar interfaces voor moet gaan ontwerpen omdat je dan een log gebeuren krijgt. Ik maak interfaces voor lastige classes zodat ik een beetje het overzicht hou en ik maak interfaces voor classes waarvan ik zeker weet dat er subclasses gaan komen + een eventuele behoefte aan proxies,decoraties etc zou kunnen zijn. Anders zet ik mijn class gewoon op mbv een abstract class en ga niet onnodig interfaces lopen introduceren die totaal niet interessant zijn.

[ Voor 36% gewijzigd door Alarmnummer op 17-06-2004 14:40 ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Verwijderd schreef op 17 juni 2004 @ 14:28:
[...]


Als jij de ontwerper bent dan bepaal jij of dat gebeurt. Met de interfaces in Java heb je een zelfde soort probleem: iemand kan net zo goed 'stiekum' een methode weghalen in de definitie van de interface die jij implementeerd. Waarom is dit zoveel verschillend dan wanneer iemand in C++ 'stiekum' een implementatie toevoegt aan wat eerst een pure abstracte base was?
Idd, iemand kan aan die interface definitie foefelen, maar, als je een goeie programmeur bent, dan roep je je member methods aan via een interface-instantie.
Als je dan die method aanroept, dan zal de compiler gaan klagen:

code:
1
2
3
4
5
void DoSomething( IMyInterface miep )
{
     miep.Process ();   // stel dat jij process uit de IMyInterface hebt gehaald, 
                         // dan compiled dit niet.
}
In C++ zou een onbedoelde 'interface' verandering onopgemerkt kunnen gaan (omdat nu logica van de 'interface' kan worden uitgevoerd ipv de logica in de sub class).
Niet als die class in C++ die je interface moet voorstellen alle methods als abstract heeft gedefinieerd.

[ Voor 3% gewijzigd door whoami op 17-06-2004 14:41 ]

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Alarmnummer schreef op 17 juni 2004 @ 14:39:
[...]

Maar het wil niet zeggen dat je dan overal maar interfaces voor moet gaan ontwerpen omdat je dan een log gebeuren krijgt. Ik maak interfaces voor lastige classes zodat ik een beetje het overzicht hou en ik maak interfaces voor classes waarvan ik zeker weet dat er subclasses gaan komen + een eventuele behoefte aan proxies,decoraties etc zou kunnen zijn. Anders zet ik mijn class gewoon op mbv een abstract class en ga niet onnodig interfaces lopen introduceren die totaal niet interessant zijn.
Daarmee ben ik het eens.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Dit vond ik net:
Recommendations on using Abstract Classes and Interfaces
1. If you anticipate creating multiple versions of your component, create an abstract class. Abstract classes provide a simple and easy way to version your components. By updating the base class, all inheriting classes are automatically updated with the change. Interfaces, on the other hand, cannot be changed once created. If a new version of an interface is required, you must create a whole new interface.
2. If the functionality you are creating will be useful across a wide range of disparate objects, use an interface. Abstract classes should be used primarily for objects that are closely related, whereas interfaces are best suited for providing common functionality to unrelated classes.
3. If you are designing small, concise bits of functionality, use interfaces. If you are designing large functional units, use an abstract class.
4. If you want to provide common, implemented functionality among all implementations of your component, use an abstract class. Abstract classes allow you to partially implement your class, whereas interfaces contain no implementation for any members.

https://fgheysels.github.io/


Verwijderd

whoami schreef op 17 juni 2004 @ 14:35:
Jij laat nu uitschijnen dat interfaces eigenlijk onnodig zijn. :?
Nee joh! :) In het geval dat jouw class in java geen base heeft, maar alleen 1 enkele interface implementeerd is een abstracte class wel hetzelfde als een interface.

Aangezien C++ MI heeft, maakt het dus niet uit of je nu voor de abstracte class een apart interface keyword hebt. De C++ is krachtiger; je kunt met hetzelfde mechanisme zowel conceptuele interfaces realiseren, een 'gewone' base classe, alswel meerdere base classes.

(Aan MI zitten natuurlijk wel haken en ogen. Een vreemde cotcha is bv dat de volgorde van de base classes uitmaakt in je classe definitie: Je kunt van een object die MI gebruikt alleen van de eerste base class een pointer to member function nemen.)

Net zoals jij je verplicht om een contract na te komen, moet de opsteller van een contract zich verplichten om het contract een contract te laten zijn, en niet opeens wat anders er van maken. Dat is een grotere verandwoordelijkheid ja. C++ programmeurs nemen die.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Maar hoe vaak gebruik jij multiple inheritance terwijl je beter een delegate (inner class die die interface/abstract class implementeerd/extend)? Het gebeurt me al niet eens vaak meer dat een class meerdere interfaces implementeerd :)

[ Voor 24% gewijzigd door Alarmnummer op 17-06-2004 15:02 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Was dit trouwens een reactie op mij of op Henk? Indien dat laatste kun je deze post negeren :)
Met die abstracte class ben je nooit zeker dat er geen implementatie in de abstracte class zit. In sommige gevallen wil je dat nl. niet.
Je gaat een beetje aan het punt voorbij waar we het aanvankelijk over hadden. Namelijk interfaces van Java vs. de lack thereof in C++.
Een interface maak je, als je aan vele verschillende classes een bepaald 'contract' wilt toekennen.
Precies, hetzelfde geldt voor een pure abstracte class in C++
Daarbij komt dan, dat bepaalde controls in .NET een property DataSource hebben, en die DataSource verwacht een object dat de IList implementeert. Hoe die methods precies geimplementeerd zijn, zal die control een worst wezen.
Idd, dus geen implementatie, dan is je ontwerp goed
Wat zou het nut geweest zijn om daar een abstracte class te gebruiken ipv een interface ? Mocht daar een abstract class gebruikt zijn, dan zou dat ontwerp imo verkeerd geweest zijn.
Alleen verkeerd als die abstracte class een implementatie biedt voor een of meerdere methoden, en al helemaal als de taal waarin je werkt geen MI ondersteunt.
Jij laat nu uitschijnen dat interfaces eigenlijk onnodig zijn. :?
Interfaces zijn nodig als MI niet ondersteund wordt. Ze zijn niets meer dan syntactische suiker als MI wel ondersteund wordt (zie ook de laatste alinea in .oisyn in "[JAVA] Implementen van een Interface d.m..."). Syntactische suiker waarvan ik het nut dus niet helemaal begrijp (en dat is waarover we aan het discussieren waren)

Wat ik probeer aan te geven is dat de enige reden waarom java en .net een echt verschil kennen tussen classes en interfaces is omdat MI niet ondersteund wordt. Een class kan niet meerdere andere classes overerven, maar dat zou betekenen dat een interface als IList ook niet geimplementeerd kan worden als je klasse al overerft van een andere klasse. Er is dus gekozen voor een duidelijke scheiding, aan de ene kant classes die je kunt overerven en die mogelijk een implementatie hebben, en aan de andere kant de echte interfaces die alleen methoden definieren zonder implementatie. In feite doe je dus wel multiple inheritance, zonder de mogelijke problemen van cyclic inheritance en het hebben van implementaties van dezelfde methode door meerdere superclasses. Ik zou het dus niets anders willen noemen dan een workaraound, want door MI volledig te ondersteunen valt het nut van aparte interface types weg. En ja, dan is het de taak van de ontwerper om te zorgen dat iets dat geen implementatie behoort te hebben ook daadwerkelijk geen implementatie krijgt, maar dat is gewoon een extra verantwoordelijkheid die je als ontwerper meekrijgt. Een verantwoordelijkheid die de ontwerper toch al een beetje had, aangezien hij in een SI taal ook had kunnen kiezen voor een abstracte class. Het enige verschil is dat ie nu wet meer mogelijkheden heeft, en dat een ontwerpfout niet zo destrastreus is in een SI taal

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: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 17 juni 2004 @ 14:58:
(Aan MI zitten natuurlijk wel haken en ogen. Een vreemde cotcha is bv dat de volgorde van de base classes uitmaakt in je classe definitie: Je kunt van een object die MI gebruikt alleen van de eerste base class een pointer to member function nemen.)
Dat is niet waar:

C++:
1
2
3
4
5
6
7
struct A { virtual void a (); };
struct B { virtual void b (); };
struct C : public A, public B { };


void (C::*a) () = &C::a;
void (C::*b) () = &C::b;


.edit: uitgebreider voorbeeld:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct A { virtual void a (); };
struct B { virtual void b (); int i; };
struct C : public A, public B { };

int C::* ci = &C::i;
int B::* bi = &B::i;

void (C::* cb) () = &C::b;
void (B::* bb) () = &B::b;

void f ()
{
    C c;
    c.*ci = 4;
    c.*bi = 34;

    (c.*cb) ();
    (c.*bb) ();
}


Compileert natuurlijk allemaal prima (anders zei ik het niet ;))

[ Voor 38% gewijzigd door .oisyn op 17-06-2004 15:30 ]

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: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Alarmnummer schreef op 17 juni 2004 @ 15:02:
Maar hoe vaak gebruik jij multiple inheritance terwijl je beter een delegate (inner class die die interface/abstract class implementeerd/extend)? Het gebeurt me al niet eens vaak meer dat een class meerdere interfaces implementeerd :)
C++ ondersteunt helaas geen inner classes (je kunt natuurlijk wel een class definieren in een class definitie, maar dat is simpelweg een namespace iets; het is zeg maar gelijk aan een static class definitie in een Java class). Je hebt gelijk dat echte MI verder vrij zeldzaam is, maar een vaak gebruikt voorbeeld is bijvoorbeeld de TeleFax. Je hebt een interface Apparaat met een methode neemOp (), 2 classes Telefoon en Fax die Apparaat implementeren, en een class die beide samenvoegt: de TeleFax. De TeleFax kijkt bij een neemOp of het om een gewoon telefoongesprek of een fax gaat, en roept aan de hand daarvan de methode van de juiste baseclass aan.

En ja, natuurlijk kun je dat oplossen door een TeleFax geen subclass te maken van Telefoon en Fax maar alleen Apparaat te implementeren, en dan gewoon 2 private members telefoon en fax te definieren aan wie je de call gaat doorsluizen. Feit is dat dat een workaround is (als iets een Telefoon verwacht kun je geen TeleFax meer geven), en dat alles wel op een bepaalde manier op te lossen is bij gemis aan features. Dat neemt niet weg dat MI in sommige gevallen gewoon erg handig is, ook al komen ze niet vaak voor. :)

[ Voor 3% gewijzigd door .oisyn op 17-06-2004 15:21 ]

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.


Verwijderd

whoami schreef op 17 juni 2004 @ 14:40:
[...]

Idd, iemand kan aan die interface definitie foefelen, maar, als je een goeie programmeur bent, dan roep je je member methods aan via een interface-instantie.
Als je dan die method aanroept, dan zal de compiler gaan klagen:

code:
1
2
3
4
5
void DoSomething( IMyInterface miep )
{
     miep.Process ();   // stel dat jij process uit de IMyInterface hebt gehaald, 
                         // dan compiled dit niet.
}
Het voorbeeld van jou klopt inderdaad als je functies weghaald uit de interface. Mischien ook wel handig om op te merken dat je bij het toevoegen of veranderen van functies nog niet eens een call hoeft te doen om een compiler fout te krijgen in java.
Niet als die class in C++ die je interface moet voorstellen alle methods als abstract heeft gedefinieerd.
Maar dat is nu juist de stelling. Iemand linkt jouw class met een onbedoeld veranderde interface (mischien een nieuwe versie van een lib), en er komt geen compiler fout maar wel veranderd gedrag.

bv

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class IFoo {
    public: virtual void doIt() = 0;
};

class FooImpl : public IFoo {

    public: void doIt() {
        std::cout << "We doen het in de implementatie" << std::endl;
    }
};


int main () { 

    
    IFoo* myIFoo = new FooImpl;

    myIFoo->doIt(); // prints : "We doen het in de implementatie"

    return 0;
}


Stel nu voor dat een onverlaat de interface veranderd: virtual wordt weggehaald en de methode krijgt een implementatie:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class IFoo {
    public: void doIt() {
        std::cout << "We doen het in de interface" << std::endl;
    }
};

class FooImpl : public IFoo {

    public: void doIt() {
        std::cout << "We doen het in de implementatie" << std::endl;
    }
};


int main () { 

    
    IFoo* myIFoo = new FooImpl;

    myIFoo->doIt(); // prints: "We doen het in de interface"

    return 0;
}


Slechte zaak: Geen compiler fout, niet eens een warning, maar wel veranderd gedrag. Wie is hier de schuldige? De maker van FooImpl? De maker van IFoo? Degene die een verkeerde versie van FooImpl met een verkeerde versie van IFoo linked? Stroustrup zelf?

Ik zou zeggen de maker van IFoo, omdat die zijn afspraken opeens niet meer nakomt.

Dit zou ophetzelfde neerkomen als eerst:

Java:
1
2
3
4
5
6
7
8
9
public interface INice {
    public void doSomethingNice();
}

public class NiceImpl implements INice {
    public void doSomethingNice() {
        // do something nice indeed
    }
}


En dan later opeens:

Java:
1
2
3
4
5
6
7
8
9
public interface INice {
    public void doSomethingNice();
}

public class NiceImpl implements INice {
    public void doSomethingNice() {
        // actually do something very bad now
    }
}


De implementatie doet nu iets anders als het contract voorschreef. De implementor is nu fout.

Verwijderd

whoami schreef op 17 juni 2004 @ 14:47:
Dit vond ik net:

[... Interfaces, on the other hand, cannot be changed once created. If a new version of an interface is required, you must create a whole new interface. ... ]
En dat is dus de reden waarom een C++ interface zonder een apart keyword nodig te hebben exact hetzelfde is als in Java. Zowel in Java als in C++ zou je een interface (contract) niet moeten veranderen nadat deze is opgesteld. Met een echt contract verwacht je ook dat de trouw van beide kanten komt, en niet alleen van diegene die het moet uitvoeren.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
.oisyn schreef op 17 juni 2004 @ 15:20:
[...]


En ja, natuurlijk kun je dat oplossen door een TeleFax geen subclass te maken van Telefoon en Fax maar alleen Apparaat te implementeren, en dan gewoon 2 private members telefoon en fax te definieren aan wie je de call gaat doorsluizen. Feit is dat dat een workaround is (als iets een Telefoon verwacht kun je geen TeleFax meer geven), en dat alles wel op een bepaalde manier op te lossen is bij gemis aan features. Dat neemt niet weg dat MI in sommige gevallen gewoon erg handig is, ook al komen ze niet vaak voor. :)
Is het een workaround om die Telefax dmv compositie v/e object Telefoon en een object Fax te maken ?
Ik denk het niet. Je zou op die manier misschien zelfs een veel onderhoudbaarder geheel hebben.
Daarnaast zou je in dit geval misschien wel een soort van strategy-pattern kunnen gebruiken: om er nog maar eens OO stellingen bij te sleuren:
- favor composition over inheritance

https://fgheysels.github.io/


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

whoami schreef op 17 juni 2004 @ 15:38:
[...]


Is het een workaround om die Telefax dmv compositie v/e object Telefoon en een object Fax te maken ?
Het is zeker geen workaround want dat is namelijk hetzelfde als die delegate oplossing. Alleen kan ik met een interne class bij de ingewanden komen van de omsluitende class en dat kan je met een normale class niet.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

whoami schreef op 17 juni 2004 @ 15:38:

Is het een workaround om die Telefax dmv compositie v/e object Telefoon en een object Fax te maken ?
ja, want een TeleFax is_a Telefoon. Op jouw manier is dat niet zo. Als Kees tegen mij zegt: "doe mij eens een telefoon, dan kan ik bellen", dan kan ik hem een TeleFax geven. Hij kan eveneens zeggen "en geef me nu eens de fax, want ik moet wat faxen". Dan geef ik 'm diezelfde TeleFax.
In programmacode heb je dus 2 functies, eentje die een Telefoon accepteert, en eentje die een TeleFax accepteert. Maar geen van de 2 functies kan ik aanroepen door gewoon de TeleFax als parameter te geven. Daar is wel weer omheen te werken (zoals altijd) door een getTelefoon () op te nemen in de TeleFax die z'n telefoon instantie terug geeft, maar dat klopt toch niet met de werkelijkheid? Ik ga toch ook geen TeleFax uit elkaar slopen omdat Kees alleen maar wil bellen, en niet wil faxen?

Kan ook wel weer opgelost worden: je maakt van Telefoon, Fax en TeleFax interfaces, en classes TelefoonImpl, FaxImpl en TeleFaxImpl die die interfaces implementeren. Je TeleFaxImpl laat je alle interfaces inheriten, en hij gebruikt intern de objecten TelefoonImpl en FaxImpl. Je gaat echter aan het punt voorbij dat het allemaal workarounds blijven voor features die je niet tot je beschikking hebt. Je kan ook gewoon MI gebruiken, dan hoef je al die moeite met interfaces en implementaties niet eens te doen.

Bovendien zijn veel patterns juist uitgevonden om om bepaalde dingen heen te werken. Denk je ook niet dat zowel jij als Alarmnummer het composiet pattern vaak gebruiken juist omdat je geen MI tot je beschikking hebt? Net als dat visitors gebruikt worden bij gebrek aan multidispatch? Net als dat het state pattern gebruikt wordt bij gebrek aan statemachine constructies in de taal zelf? Ik noem maar een paar voorbeelden :)

[ Voor 34% gewijzigd door .oisyn op 17-06-2004 15:58 ]

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.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
.oisyn schreef op 17 juni 2004 @ 15:43:
[...]


ja, want een TeleFax is_a Telefoon.
Hmm, een TeleFax kan ook een telefoon en een fax hebben.
Net zoals je kunt zeggen dat een Window in Windows een Rectangle heeft waarop hij z'n 'dingen' toont, en niet noodzakelijk een Rectangle is.
Sterker zelfs, door een Window een member van het type Shape te geven, zou je in principe ook Windows moeten kunnen hebben die cirkels, driehoeken, .... zijn.

[ Voor 21% gewijzigd door whoami op 17-06-2004 15:51 ]

https://fgheysels.github.io/


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

(heb m'n vorige post trouwens geedit)

Dat vind ik een beetje een dom voorbeeld, een Window is namelijk helemaal geen Rectangle, en bovendien toont hij z'n dingen niet op een rectangle, maar op het scherm (een rectangle is niets meer dan een positie en een grootte), en de vraag is of ie er ook daadwerkelijk wel een heeft. Het hebben van een rectangle is namelijk niet een essentieel iets voor een Window, hij kan prima werken zonder dat ie weet waar ie zich bevindt. Het is puur voor het OS van belang om te bepalen waar de window getekend moet worden, en wanneer hij mouse events moet sturen naar de window. Daarnaast is een Rectangle gewoon een data-type, het heeft geen methoden en dus geen implementatie.

En een WerkNemer is toch ook een Persoon? Hij heeft toch geen Persoon? Waarom zou het voor een apparaat als een telefax ineens anders zijn? Het is hetzelfde ding, het kan alleen meer. Net als dat een WerkNemer meer kan

[ Voor 6% gewijzigd door .oisyn op 17-06-2004 15:56 ]

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.


Verwijderd

.oisyn schreef op 17 juni 2004 @ 15:11:

Dat is niet waar:

[...]

Compileert natuurlijk allemaal prima (anders zei ik het niet ;))
Ik bedoelde een iets andere situatie waarbij je de pointer to member functions op een pointer naar een base class toepast. Dus:

C++:
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
#include <iostream>

struct A { virtual void a () { std::cout << "A"; }; };
struct B { virtual void b () { std::cout << "B"; }; };

struct C : public A, public B { 
    virtual void a () { std::cout << "AC"; };
    virtual void b () { std::cout << "BC"; };
};

typedef void(A::* FuncA)(void);
typedef void(B::* FuncB)(void);

int main() {
    FuncA funcA = &A::a;
    FuncB funcB = &B::b;
    
    A* cA = new C;    
    (cA->*funcA) ();

    B* cB = new C;
    (cB->*funcB) ();

    return 0;
}


Ik probeerde het net even met VS 7.1 en het werkt!

Ik weet echter vrij zeker dat het niet werkte met VS 7.0 (die ik nu helaas niet installed heb). In mijn developper 'dagboek' van het project waar ik toen aan werkte heb ik er zelfs nog een aantekening over gemaakt. Ik kan me vaagjes iets herinneren dat het ook een expliciete compiler foutmelding gaf, iets in de trend van "can only apply pointer to member to first base" of iets in die richting. Of ik ben gek :) Dat kan natuurlijk ook...

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
.oisyn schreef op 17 juni 2004 @ 15:43:
[...]

Bovendien zijn veel patterns juist uitgevonden om om bepaalde dingen heen te werken. Denk je ook niet dat zowel jij als Alarmnummer het composiet pattern vaak gebruiken juist omdat je geen MI tot je beschikking hebt?
Hmm, die patterns zijn niet ontworpen met het oog op talen die geen MI hebben. Ze zijn dus ook niet opgesteld als 'work-around' voor MI.
Sterker zelfs, het GoF boek is uitgebracht in '94 dacht ik; van Java en C#was er toen nog geen sprake. De code-voorbeelden zijn dan ook in C++, waar je dus wel MI hebt.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
.oisyn schreef op 17 juni 2004 @ 15:56:
En een WerkNemer is toch ook een Persoon? Hij heeft toch geen Persoon? Waarom zou het voor een apparaat als een telefax ineens anders zijn? Het is hetzelfde ding, het kan alleen meer. Net als dat een WerkNemer meer kan
Het Window was misschien een dom voorbeeld;
Echter, in bovenstaand voorbeeld van jou ga je inderdaad een Werknemer van Persoon inheriten. Hier zou het dom zijn om mbhv composition te werken.
Composition ga je gebruiken als een bepaald iets op een andere manier kan geimplementeerd worden.

Je hebt bv. een abstracte class (of een interface) 'Dier', daar ga je classes 'Vogel', Paard, Vis van inheriten.
Ieder dier kan zich voortbewegen, maar dat gaat voor ieder dier op een andere manier gebeuren. Hier kan je dus een abstracte class of interface 'Mouvement' voor gebruiken; een dier heeft dan een instance van mouvement.
Voor een vogel zal dat 'Vliegen' zijn, voor een vis zwemmen, etc...

https://fgheysels.github.io/


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

whoami schreef op 17 juni 2004 @ 16:21:
[...]
Je hebt bv. een abstracte class (of een interface) 'Dier', daar ga je classes 'Vogel', Paard, Vis van inheriten.
Ieder dier kan zich voortbewegen, maar dat gaat voor ieder dier op een andere manier gebeuren. Hier kan je dus een abstracte class of interface 'Mouvement' voor gebruiken; een dier heeft dan een instance van mouvement.
Voor een vogel zal dat 'Vliegen' zijn, voor een vis zwemmen, etc...
Precies.

Het probleem is dat je met extenden dan helemaal ondersneeuwt in alle subclasses VliegenVogel, ZwemmendeVogel, LopendeVogel, ZwemmendeVis,KruipendeVis,VLiegendeVis.

En het gaat helemaal lachen worden als je ook weer combinaties gaat krijgen, bv een werknemer die directeur is en personeelsmanager. Je krijgt dan een ware class explosie en dan is het een stuk praktisch om het met een compostie op te lossen.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Persoon{
     Set<Rol> getRollen(){...}
}

interface Rol{
     void werk(Persoon p);
}

class Personeelsmanager implements Rol{
      void werk(Persoon p){... ontsla ze allemaal}
}

class Directeur implements Rol{
     void werk(Persoon p){...}
}

[ Voor 3% gewijzigd door Alarmnummer op 17-06-2004 16:37 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 17 juni 2004 @ 16:13:
Ik weet echter vrij zeker dat het niet werkte met VS 7.0 (die ik nu helaas niet installed heb). In mijn developper 'dagboek' van het project waar ik toen aan werkte heb ik er zelfs nog een aantekening over gemaakt. Ik kan me vaagjes iets herinneren dat het ook een expliciete compiler foutmelding gaf, iets in de trend van "can only apply pointer to member to first base" of iets in die richting. Of ik ben gek :) Dat kan natuurlijk ook...
Dan ligt het natuurlijk aan de compiler, en niet zozeer aan de C++ standaard. Om te controleren of iets zou moeten werken gebruik ik altijd de online testversie van comeau. Als Comeau het niet accepteert weet je vrijwel zeker dat het niet mag volgens de standaard ;)

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.


Verwijderd

Topicstarter
curry684 schreef op 17 juni 2004 @ 01:50:
[...]

Ik zei al dat het (D)COM was, wat door VB, Java (!), C++, .NET en weet ik het wat gebruikt kan worden. Het ging me echter enkel om het principe, dit kun je in Java namelijk ook implementeren.

Echter, het is namelijk wederom een ranzige workaround om iets dat je in OOP gewoon niet moet willen: service without contract. Maar minder ranzig dan bytecode alteration.
Service without contract?
Wat als dat spreekwoordelijke contract er wel is, maar onzichtbaar is voor een applicatie?
[...]

COM in het algemeen wordt dan ook door de hele wereld (incluis Microsoft) gezien als Microsoft's stomste fout ooit.
Mja, dat geloof ik best, maar waar ik het over heb maakt wat mij betreft geen deel uit van die fout.

Verwijderd

btw beste Cybarite, ik weet dat het moeilijk is om alle berichten en code examples te doorlezen (het zijn er nogal veel geworden), maar je hebt de volgende vraag nog steeds niet beandwoord:

Is reinterpret_cast niet gewoon waarna je op zoek was in java?

Verwijderd

Topicstarter
Verwijderd schreef op 17 juni 2004 @ 17:39:
btw beste Cybarite, ik weet dat het moeilijk is om alle berichten en code examples te doorlezen (het zijn er nogal veel geworden), maar je hebt de volgende vraag nog steeds niet beandwoord:

Is reinterpret_cast niet gewoon waarna je op zoek was in java?
Ik heb zojuist de nieuwe posts doorgelezen, maar die zijn allemaal ietwat offtopic. B)

Ik kan weinig casten, aangezien ik een Interface implement, en geen abstract class extend. Verder zou ik niet weten hoe ik een reinterpret_cast kan uitvoeren als ik het over het implementen van een Interface heb...

Ik kan gewoon totaal geen operaties uitvoeren op een geimplemente Interface...

Met een abstract class zou ik dat misschien nog wel kunnen doen (er vanuit gaande dat 'super' kunstmatig niet werkt bij het implementen van Interfaces); reinterpret_cast(super); :o.
Als iets in die geest uberhaupt al kan lijkt dit me vrij linke soep... :P

edit:
Maar wil iedereen proberen bij Java te blijven want van C/C++/.Net/etc heb ik weinig kaas gegeten, en of het daar wel of niet kan is irrelevant voor de taal Java.

[ Voor 13% gewijzigd door Verwijderd op 17-06-2004 18:04 . Reden: toevoeging ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

henk_DE_man: Volgens mij niet, en wat heeft ie daar überhaupt aan dan? In C++ gaat zoiets ook niet werken; de reden waarom jouw voorbeeld werkt is omdat de compiler de types kent, en dus ook wat je dynamic_reinterpret_cast returnt. De compiler weet dus welke test () aangeroepen moet worden, omdat het type bekend is.

Wat Cybarite wil is het volgende:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// de interface die geimplementeerd moet worden, alleen bekend door Cybarite,
// niet door de compiler
class MyInterface
{
public:
    virtual void func1 () = 0;
    virtual void func2 () = 0;
};

// de daadwerkelijke implementatie
class MyClass
{
public:
    virtual void func1 () { std::cout << "MyClass::func1 ()" << std::endl; }
    virtual void func2 () { std::cout << "MyClass::func2 ()" << std::endl; }
};

MyInterface * convertToInterface (MyClass * pClass)
{
    // wat nu? Als je mazzel hebt werkt een reinterpret_cast,
    // maar alleen als de vtables exact overeenkomen
}


Wat hier moet gebeuren is het aanmaken van een proxy, die MyInterface implementeert en de calls doorsluist naar een MyClass.

Waarom Cybarite dit probleem heeft is me niet helemaal duidelijk, maar ik heb een vermoeden dat MyClass een soort van plugin is die via een classloader wordt ingeladen. En bij het implementeren van de plugin heeft hij geen beschikking over de interfaces die geimplementeerd moeten worden (maar als persoon heeft ie er natuurlijk wel kennis over). Ik denk dat een oplossing door een Proxy toch het beste is. Wat hij dan wel moet doen is zorgen dat MyClass een InvocationHandler implementeert (hetzelfde als de IDispatch waar curry het over had), en dus in de invoke () methode de calls doorsluist naar de juiste methode. Op die manier is bij het implementeren van MyClass de MyInstance niet nodig. InvokeHandler natuurlijk wel, maar dat is een standaard java klasse en dat moet dus geen probleem zijn lijkt me. En als dat wel een probleem is dan heeft ie vet pech, want dan is er gewoon geen oplossing zonder byte-code generation :Y)

[ Voor 39% gewijzigd door .oisyn op 17-06-2004 18:14 ]

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.


Verwijderd

Topicstarter
.oisyn heeft het wel door denk ik. :)

Zou je:
C++:
1
MyInterface * convertToInterface (MyClass * pClass) 


Even uit kunnen leggen, is namelijk vrij cruciaal wil ik verzekerd zijn dat jij/andere C'ers het goed begrijpen.

Wat ik begrijp is dat er wat gerotzooid wordt met pointers in die code?
Maar is deze syntax denkbeeldig of werkt dit echt?
Het komt op mijn nl. een beetje onbekend over, maar ja ik heb nog geen C compiler aangeraakt (met eigen code dan) :P....

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Cybarite: ik heb een stuk toegevoegd aan mijn vorige post wat voor jou denk ik wel van belang is (nofi dat ik over je praatte in de 3e persoon, ik had het immers tegen Henk ;)). Ik gebruikte de C++ code om het uit te leggen aan Henk, aan casts heb jij weinig omdat je in java niet zomaar met pointers kunt werken.

Ik heb verder geen verstand van die InvocationHandler van java, maar je moet het ongeveer zo zien:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass implements java.lang.reflect.InvocationHander
{
    // functies van MyInterface
    void func1 () { System.out.println ("func1"); }
    void func2 () { System.out.println ("func2"); }

    void invoke (String name, Object[] params)
    {
        if (name.equals ("func1"))
            func1 ();
        else if (name.equals ("func2"))
            func2 ();
    }
}


Let wel, dit is dus niet letterlijk de manier waarop InvocationHandler echt werkt, maar puur om je een idee te geven hoe het ongeveer in elkaar zit :)

Het idee is vervolgens dat je je MyClass laadt met een classloader, en dan een Proxy vanuit code aanmaakt die MyInterface implementeert en je MyClass instantie gebruikt om de calls naar door te sluizen

[ Voor 10% gewijzigd door .oisyn op 17-06-2004 18:22 ]

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.


Verwijderd

Verwijderd schreef op 17 juni 2004 @ 18:00:
[...]


Ik heb zojuist de nieuwe posts doorgelezen, maar die zijn allemaal ietwat offtopic. B)

Ik kan weinig casten, aangezien ik een Interface implement, en geen abstract class extend. Verder zou ik niet weten hoe ik een reinterpret_cast kan uitvoeren als ik het over het implementen van een Interface heb...
Kijk! :) Dan zijn de nieuwe posts (sommige dan), toch minder off topic als je denkt. Namelijk, een interface is eigenlijk niets anders dan inheritance van een pure abstracte base class.

Ik heb een groot vermoeden dat jij gewoon de term "interface laten implementeren" verkeerd gebruikt. Namelijk, je zei ergens hierboven dat de class (en dus ook het object van die class) de benodigde methoden al had geimplementeerd. Met de term "interface laten implementeren" denken veel mensen dat je at runtime methodes aan een class wilt gaan toevoegen. Dat is dus duidelijk niet de bedoeling.

Wat je dus (als ik het goed heb) bedoelt, is dat een object alleen maar opgevat hoeft te worden als het type van een interface. Dit is precies wat een cast doet. De gewone c-style cast kijkt in de class definitie of een cast mag. Dit mag als het target type in de inheritance-chain voorkomt, of in een van de geimplementeerde interfaces. Conceptueel is een interface ook gewoon inheritance, maar dan alleen van een type.

Bv

Java:
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
public class Base {

    public void something() {}

}

public interface ISomething {
    public void something();
}

public class Sub extends Base implements ISomething {

    public void something() {}

}

// in some function of some class
void f() {

    Base base = new Sub();
    
    ISomething iSomething = (ISomething) base; // cast
    Sub sub = (Sub) base; // cast

}


Zoals je boven ziet doe je dus in beiden gevallen een cast om een pointer naar Base als een ISomething of als een Sub te beschouwen. Dit is equivalent met wat in andere talen wel een dynamic cast wordt genoemt.

Aanschouw nu de volgende code sequentie:


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Base {
    public void something() {}
}

public interface ISomething {
    public void something();
}

public class Sub extends Base /*implements ISomething 'vergeten' */ {
    public void something() {}
}

// in some function of some class
void f() {

    Base base = new Sub();
    
    ISomething iSomething = (ISomething) base; // cast, not allowed right now
    Sub sub = (Sub) base; // cast

}


De cast is nu niet toegestaan omdat je de compiler niet hebt verteld dat je dit wilt toestaan. In jouw hypothetische geval was het dus een kwestie van niet kunnen vertellen.

Nu komt de reinterpret cast om de hoek kijken. Bij het gebruik van dezelfde classes, een nieuwe f functie:

C++:
1
2
3
4
5
6
7
8
void f() {

    Base* base = new Sub();
    
    ISomething iSomething = reinterpret_cast<ISomething*>( base); // cast enforced
    Sub* sub = (Sub*) base; // cast

}

Verwijderd

Topicstarter
.oisyn schreef op 17 juni 2004 @ 18:05:
Wat hier moet gebeuren is het aanmaken van een proxy, die MyInterface implementeert en de calls doorsluist naar een MyClass.
Daar zou ik best mee kunnen leven ja, maar misfire schoot het idee van iemand over een dynamic proxy eerder al vrij overtuigend af. ;)
Waarom Cybarite dit probleem heeft is me niet helemaal duidelijk, maar ik heb een vermoeden dat MyClass een soort van plugin is die via een classloader wordt ingeladen.
Je slaat de spijker op z'n kop, dit probleem haalde ik mezelf op de hals en daarom zei ik al dat ik het allang heb opgelost. Blijft echter wel dit interessante vraagstuk open staan.
En inderdaad, alles wordt via een ClassLoader geladen (kan geen (relevante) imports doen, zei ik al eerder).
En bij het implementeren van de plugin heeft hij geen beschikking over de interfaces die geimplementeerd moeten worden (maar als persoon heeft ie er natuurlijk wel kennis over).
Precies, maar voor alle duidelijkheid: ik kan dus wel instances van MyClass maken.
Ik denk dat een oplossing door een Proxy toch het beste is. Wat hij dan wel moet doen is zorgen dat MyClass een InvocationHandler implementeert (hetzelfde als de IDispatch waar curry het over had), en dus in de invoke () methode de calls doorsluist naar de juiste methode. Op die manier is bij het implementeren van MyClass de MyInstance niet nodig.
Hoe bedoel je de calls doorsluist?
Als MyClass hier in feite 'MyInterface' is, kun je toch niks doorsluizen?
Want dat is waar jullie het net over hadden, dan ga je zelf implementations toevoegen/de definitie van de Interface niet strikt navolgen (extra methoden)...
Of geldt dit niet als die methoden private/protected zijn?
Of dat ik gewoon een 'meta'-class maak, die de communicatie tussen MyInterface en MyClass verzorgt? Maar dan moet bij één van beiden de definitie van MyInterface wel bekend zijn...
Ik kan dan ook een kunstmatig raakvlak maken van beide 'classes' (waarvan één Interface dus), zodat beiden weten welke methode ze kunnen aanroepen om met elkaar te communiceren?
Dit stukje twijfel ik nog over, ik heb dus wel een MyInstance (van MyClass).
Maar de 'MyInterface' heb ik dus niet volgens de JVM....
InvokeHandler natuurlijk wel, maar dat is een standaard java klasse en dat moet dus geen probleem zijn lijkt me. En als dat wel een probleem is dan heeft ie vet pech, want dan is er gewoon geen oplossing zonder byte-code generation :Y)
Hehe, zeker niet, want als ik de standaard Java libraries niet kon importen is het onmogelijk om de applicatie te kunnen laten draaien (ook niet via ClassLoaders ;)). :D

edit:
Ik kreeg de indruk dat er een definitieverwarring is over MyClass en MyInterface, dus ik houd met beide begrippen rekening in m'n reactie. Ik heb je code niet meer bekeken dus later corrigeer ik wellicht nog het eea, maar ik moet nu eerst ff op Henk reageren. :+

[ Voor 7% gewijzigd door Verwijderd op 17-06-2004 18:47 ]


Verwijderd

Topicstarter
Verwijderd schreef op 17 juni 2004 @ 18:34:
[...]


Kijk! :) Dan zijn de nieuwe posts (sommige dan), toch minder off topic als je denkt. Namelijk, een interface is eigenlijk niets anders dan inheritance van een pure abstracte base class.
Dat weet ik, en ik zeg later ook dat me nog onduidelijk is hoe Java dat afhandelt...
Ik zie Java (de compiler dan) er best voor aan dat ze hier kunstmatig restricties aan opleggen, om de iedere indruk weg te nemen dat een interface niets meer is dan een volledig abstracte class... :|
Ik heb een groot vermoeden dat jij gewoon de term "interface laten implementeren" verkeerd gebruikt. Namelijk, je zei ergens hierboven dat de class (en dus ook het object van die class) de benodigde methoden al had geimplementeerd. Met de term "interface laten implementeren" denken veel mensen dat je at runtime methodes aan een class wilt gaan toevoegen. Dat is dus duidelijk niet de bedoeling.
Hehe, daarover zal best verwarring zijn ontstaan ja, maar ik zeg vrij duidelijk wat ik wil inclusief het feit dat ik al deze methoden al heb geimplement in m'n code van de class, maar dat het slechts om een formaliteit gaat wat betreft het 'implements'-keyword in Java waardoor Java de Interface in kweste ook daadwerkelijk officieel laat implementen. Als iedereen gewoon secuur leest wat ik zeg, en er zelf niets bijdenkt dan zou je men niet verward zijn. :)
Wat je dus (als ik het goed heb) bedoelt, is dat een object alleen maar opgevat hoeft te worden als het type van een interface.
Nee, dat is niet relevant, aangezien ik een Interface toch niet los kan instantiaten, zoals iemand al opmerkte. Het gaat me er om dat die Interface officieel geimplement moet worden door een bepaald Object. En dus dit Object genotificeerd wordt van Events die optreden binnen de Interface, waarvoor de Interface dus meestal wordt gebruikt. ;)
(Dit om het verhaal even compleet te maken. :))
Dit is precies wat een cast doet. De gewone c-style cast kijkt in de class definitie of een cast mag. Dit mag als het target type in de inheritance-chain voorkomt, of in een van de geimplementeerde interfaces.
Precies, maar aan die voorwaarden kan (offcieel) niet worden voldaan. Toch is het een safe cast, maar dat weet alleen de programmeur.
Het is ook niet dat ik willekeurige parameters accepteer voor deze operatie oid, ik werk met ClassLoaders, en geef hard op over welk type(s) ik het heb. Feitelijk dus net zo veilig als conventionele Java-syntax, maar dat kan de (huidige) compiler natuurlijk niet controleren....
Conceptueel is een interface ook gewoon inheritance, maar dan alleen van een type.
Dan ga je C++ en Java door elkaar gooien. Deze vergelijking klopt wel, maar is praktisch niet erg veelbetekenend aangezien Java en C++ wat dit betreft niet compatible zijn, en dat ook niet zijn te maken. Dus jij weet wat het synoniem zou kunnen zijn van een bepaalde logische constructie van C++ onder Java, maar dat kun je Java natuurlijk niet aan het verstand peuteren.
Bv

Java:
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
public class Base {

    public void something() {}

}

public interface ISomething {
    public void something();
}

public class Sub extends Base implements ISomething {

    public void something() {}

}

// in some function of some class
void f() {

    Base base = new Sub();
    
    ISomething iSomething = (ISomething) base; // cast
    Sub sub = (Sub) base; // cast

}
Heel nifty ja, maar helaas kan ik die Interface met geen mogelijkheid instantieren....
Dit zou niet kunnen in Java, zo heb ik dus vernomen (wederom een kunstmatige restrictie uit purisme van de eigen definitie).
En last but not least, het type van de Interface is mij dus officieel onbekend!
Maar de Java reflection API kan zogezegd naast voorzien in een ClassLoader-functionaliteit, ook de Fields ed van een ingeladen class/type exporteren. Mijn vraag is dus of dit het dynamisch officieel implementen van Interfaces mogelijk maakt.
Aanschouw nu de volgende code sequentie:


Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Base {
    public void something() {}
}

public interface ISomething {
    public void something();
}

public class Sub extends Base /*implements ISomething 'vergeten' */ {
    public void something() {}
}

// in some function of some class
void f() {

    Base base = new Sub();
    
    ISomething iSomething = (ISomething) base; // cast, not allowed right now
    Sub sub = (Sub) base; // cast

}


De cast is nu niet toegestaan omdat je de compiler niet hebt verteld dat je dit wilt toestaan. In jouw hypothetische geval was het dus een kwestie van niet kunnen vertellen.

Nu komt de reinterpret cast om de hoek kijken. Bij het gebruik van dezelfde classes, een nieuwe f functie:

C++:
1
2
3
4
5
6
7
8
void f() {

    Base* base = new Sub();
    
    ISomething iSomething = reinterpret_cast<ISomething*>( base); // cast enforced
    Sub* sub = (Sub*) base; // cast

}
Enforcen... maar wat?
Probleem is niet alleen dat Java me dit niet toestaat, ik heb gewoon het type niet...
Ik weet nogmaals niet of er een class Interface in de Java reflection API bestaat, maar als zou dat zo zijn, dan is dat nog niet het equivalent van een interface... (met kleine I dus).

Als dat wel zo was, zou dit namelijk moeten werken:
Java:
1
2
Class Klasse = Class.forName("net.tweakers.forum.PEnW");
Klasse subforum = new PenW();

In dit voorbeeld heb ik expres "Klasse" gebruikt.
Want dit bewijst dus dat Klasse in feite classObject is, en subforum een classObjectInstance....

Ze zijn dus niet uitwisselbaar met het conventionele type class en interface (is ook niet zo onverwacht ;)), en aan casten heb ik dus vrij weinig.

Tja, if only Java had explicit pointers... >:)
Dan zou ik wat 'dirty' werk niet schuwen hoor. :)


edit
Als mijn studiejaar is afgerond (na volgend weekend, als ik daarna geen tijd weet te vinden over een ruime week) zal ik hier eens meer over uitzoeken net als nog wat gevaarlijke truucjes die ik ondertussen al heb bedacht, vooral rond abstracte classes... >:)

[ Voor 6% gewijzigd door Verwijderd op 17-06-2004 19:23 . Reden: post scriptum ]


Verwijderd

Verwijderd schreef op 17 juni 2004 @ 19:17:

[...]
maar dat het slechts om een formaliteit gaat wat betreft het 'implements'-keyword in Java waardoor Java de Interface in kweste ook daadwerkelijk officieel laat implementen.

[Wat je dus (als ik het goed heb) bedoelt, is dat een object alleen maar opgevat hoeft te worden als het type van een interface.]

Nee, dat is niet relevant, aangezien ik een Interface toch niet los kan instantiaten, zoals iemand al opmerkte.

Het gaat me er om dat die Interface officieel geimplement moet worden door een bepaald Object.
Bingo! Volgens mij hebben we hier de hele clue van het verhaal. Jij bent wel thuis in de informatica, maar meer op een hoger niveau. Je hebt je waarschijnlijk nog niet of weinig bezig gehouden met hoe zulke dingen op machine niveau geimplementeerd worden.

Als je naar de memory layout en vtable van een class kijkt, dan is het opvatten van een pointer van het ene type als een pointer van het andere type precies het zelfde als wanneer dat eerste type 'officieel' zou zeggen dat het ook dat andere type is. Tenminste... voorzover de memory layout toevalligerwijs overeenkomt. Als dat zo is heb je geluk, maar je hebt niet die garantie. Zie mijn bovenstaande voorbeeld waar ik 2 compleet ongerelateerde classen naar elkaar cast, en waar dat (toevallig) goed gaat.

Ik denk dat het heel belangrijk is voor deze discussie dat je dat begrijpt. Als je vanuit de functionele hoek komt is het mischien even een gedachten twist die je moet maken. (Ik weet nog dat ik een zelfde soort twist moest maken toen ik voor het eerst wat met functionele en logische talen moest doen).

Een object opvatten als het type van een interface is dus heel sterk wel relevant en heeft ook nix te maken met het instantiaten van een interface (wat dus niet kan).

Mischien dat 2 simpele illustraties een beetje helpen. Stel je 2 classen voor die allebei 3 gelijknamige data members hebben, 1 int, een char en nog een 1.

In het geheugen staat die mischien als

class 1:
$[allocation address]
+ 0 : 32 bits (integer a)
+ 4 : 8 bits (char b)
+ 5 : 32 bits (integer c)

class 2:
$[allocation address]
+ 0 : 32 bits (integer a)
+ 4 : 8 bits (char b)
+ 5 : 32 bits (integer c)

De addressen en types komen precies overeen. Stel je hebt een pointer naar class 1 op address $1000. Als je nu tegen de compiler zegt dat je integer c wilt vullen met 50 dan komt er ongeveer in pseudo machine code iets te staan als:

store $1000+5, #50

Als je nu tegen de compiler 'liegt' en zegt dat op address $1000 geen object van classe 1 staat, maar van classe 2, en je wilt vervolgens van classe 2 integer c vullen, dan gaat het in dit simpele geval goed. Er wordt namelijk precies dezelfde machine code voor gegenereerd. IHA heb je deze garantie echter niet.

Als je nu een pointer (in java) naar een interface zou casten, dan genereerd de compiler precies die code alsof het object op die plaats in het geheugen -wel- die interface had geimplementeerd. -Als- de layout en vtable (of java's equivalent daarvan) precies overeenkomen dan gaat dat dus goed, anders gaat het gruwelijk fout. C en C++ programmeurs nemen soms deze verandwoordelijkheid.
De compiler kan dit echter niet controleren, dus is het niet toegestaan in Java. In java mag je niet rommelen met pointers. Daarom stelde ik ook dat enkel conceptueel de reinterpret_cast precies zou doen wij jij wilde. Uit .oisyn's post van Thursday 17 June 2004 18:05 blijkt dat dat ook inderdaad zo is.
Precies, maar aan die voorwaarden kan (offcieel) niet worden voldaan. Toch is het een safe cast, maar dat weet alleen de programmeur.
Functioneel gezien is het een safe cast, maar practisch gezien hoeft dat helemaal niet zo te zijn. -Alleen- als de compiler voor de interface en het object dezelfde vtable genereerd zou het werken. Dit valt echter buiten de language spec, en is dus undefined behaviour. Als het op jouw compiler werkt is dat toevallig.
Oh, voor als je niet weet wat een vtable is, heel simpel gezegd: een array met verwijzingen naar functies die runtime (achter de schermen) doorlopen wordt om mbt polymorfisme de juiste functie implementatie te vinden.
[Conceptueel is een interface ook gewoon inheritance, maar dan alleen van een type.]

Dan ga je C++ en Java door elkaar gooien. Deze vergelijking klopt wel, maar is praktisch niet erg veelbetekenend aangezien Java en C++ wat dit betreft niet compatible zijn, en dat ook niet zijn te maken.
Het heeft ook niks te maken met of C++ of Java hetzelfde zijn, of compatible of niet, het gaat om de concepten. Ook in java in conceptueel gezien een interface inheritance. Ook in java heb je pointers. Sterker nog, je hebt in java alleen maar heap gealloceerde objecten, en dus alleen maar pointers. Java heeft ook geen call bij reference semantics, maar alleen call by value: pointers worden by value doorgegeven, etc, etc. Dat de dingen anders heten betekent niet dat de concepten verschillen.
Heel nifty ja, maar helaas kan ik die Interface met geen mogelijkheid instantieren....
Dit zou niet kunnen in Java, zo heb ik dus vernomen (wederom een kunstmatige restrictie uit purisme van de eigen definitie).
Heeft deze comment nou betrekking op mijn code sample of op jouw code? Wat ik opschreef is gewoon standaard java hoor. Als je een pointer naar een base hebt in Java kun je gewoon naar een van de feitelijke types casten.

Hier komt al om de hoek kijken dat een interface implementen hetzelde is als inheritance, want via de instanceof operator en de cast maakt Java geen enkel onderscheid tussen beiden.

Bv

Java:
1
2
3
4
5
if (base instanceof ISomething)
    // ....

if (base instanceof Sub)
   // ....


Tevens je instantieert ook hier niet een interface: je maakt een instantance van een class (dat kun je, had je eerder gezegd), en die instance cast je naar het type van de interface.
En last but not least, het type van de Interface is mij dus officieel onbekend!
Dat is wel het allerbelangrijkst, en in een van mijn eerste posts in deze thread had ik je ook al hierna gevraagt (maar je gaf geen antwoord hierop). Echter, -waar- is het type van de Interface onbekend?

Iniedergeval dus op de plek waar je class de interface zou moeten implementeren, maar ook op de plek waar je de ingelade code gaat gebruiken?

Er zal toch ooit ergens in de code een plek moeten zijn waar iemand de interface wel kent. Stel namelijk dat in de gehele code base nergens de interface bekend is, dus niet in de classes die je dynamisch laadt als plug-in, en niet in de code die dat laden uitvoert, dan heb je toch ook nergens die interface nodig?

Nou, duidelijk is dat dus niet zo, dus er komt ergens een plek die de interface wel kent. Nou, op dat moment kun je dus die denkbeeldige java reinterpret_cast doen.
Als mijn studiejaar is afgerond (na volgend weekend, als ik daarna geen tijd weet te vinden over een ruime week)
Check net pas je profiel en blijkt dus student HBO-IN te zijn. Kwa vraagstelling enzo zat ik eigenlijk aan een student van de universiteit nijmegen te denken :)


zal ik hier eens meer over uitzoeken net als nog wat gevaarlijke truucjes die ik ondertussen al heb bedacht, vooral rond abstracte classes... >:)[/quote]

Verwijderd

Topicstarter
Verwijderd schreef op 17 juni 2004 @ 20:54:
[...]


Bingo! Volgens mij hebben we hier de hele clue van het verhaal. Jij bent wel thuis in de informatica, maar meer op een hoger niveau. Je hebt je waarschijnlijk nog niet of weinig bezig gehouden met hoe zulke dingen op machine niveau geimplementeerd worden.
Wel, maar ik accepteer het niet. ;)
En ik ga niet roepen dat ik dat zelf maar aan ga passen oid (in een of andere high-level taal oid), omdat ik dat mogelijk (:P) niet kan, en omdat dat raar over komt.
Bovendien; waarom is iets onconventioneels als reflection wél mogelijk, maar dit aspect daaraan niet? :?
Ik denk dat als Sun hier voor te porren is (MS heeft het ook :P) dat ze deze functionaliteit wel toevoegen.
Maar (nee .oysin, ik ben het niet vergeten ;)) is dit niet mogelijk dmv die dynamic proxies in Java? Misfire ontkende dat, zoals ik al zei, bijzonder overtuigend.
Maar goed, als niemand het kan zeggen, dan zal ik het wanneer ik tijd heb eens proberen. :)
Als je naar de memory layout en vtable van een class kijkt, dan is het opvatten van een pointer van het ene type als een pointer van het andere type precies het zelfde als wanneer dat eerste type 'officieel' zou zeggen dat het ook dat andere type is.
Precies, dat begrijp ik ook wel, ik ben qua "machinale" talen een frequent beoefenaar van assembly. ;)
Maar wat is de vtable? :?
Is dat het definitiegedeelte (fields, methods, etc) van een class zoals C deze spiegelt in het geheugen?
Tenminste... voorzover de memory layout toevalligerwijs overeenkomt. Als dat zo is heb je geluk, maar je hebt niet die garantie. Zie mijn bovenstaande voorbeeld waar ik 2 compleet ongerelateerde classen naar elkaar cast, en waar dat (toevallig) goed gaat.
Maar dat gaat niet op voor een "class" versus een "Class"...
Wat op zich geen ramp zou moeten zijn, als Class voldoende functionaliteit zou bevatten om ook mijn vraagstuk te realiseren.
Ik denk dat het heel belangrijk is voor deze discussie dat je dat begrijpt. Als je vanuit de functionele hoek komt is het mischien even een gedachten twist die je moet maken. (Ik weet nog dat ik een zelfde soort twist moest maken toen ik voor het eerst wat met functionele en logische talen moest doen).
Ja, gelukkig heb ik me éérst verdiept in imperatieve talen. Maar deze zijn ook wat meer praktisch gericht, en mijn activititeiten qua functioneel programmeren zijn hooguit hobbyisme,
offtopic:
Maar om ff offtopic te zijn (mag ik ook wel ff nu he? :P): ik heb er daar ooit eens over nagedacht, en ik zag de discussies over het nut van threads (zoals gebruikt in imperatieve talen) al voor me...
Want als je programmeert met bijv. de Lambda Calculus, kunnen deze "stromen" gesymboliseert als "threads", compile-time worden bepaald...
Behalve als je polymorfe code hebt natuurlijk, maar ja, volgens mij is dat niet echt de bedoeling van een niet-machinale taal...
Dan moet je het morferingsproces als een soort bacteriedeling opvatten, waarbij de 1e bacterie de oude binary is, en de 2e de nieuwe. En de oude sterft dan af later natuurlijk...
Zo zie je maar weer, komt toch heel wat bij kijken, die verschillen in talen\inzichten. :)
Wat zou Edsger Dijkstra of Donald Knuth er van vinden... :o
Een object opvatten als het type van een interface is dus heel sterk wel relevant en heeft ook nix te maken met het instantiaten van een interface (wat dus niet kan).
Dat snap ik, maar hoe wil je Java dat laten doen...
Mischien dat 2 simpele illustraties een beetje helpen. Stel je 2 classen voor die allebei 3 gelijknamige data members hebben, 1 int, een char en nog een 1.

In het geheugen staat die mischien als

class 1:
$[allocation address]
+ 0 : 32 bits (integer a)
+ 4 : 8 bits (char b)
+ 5 : 32 bits (integer c)

class 2:
$[allocation address]
+ 0 : 32 bits (integer a)
+ 4 : 8 bits (char b)
+ 5 : 32 bits (integer c)

De addressen en types komen precies overeen. Stel je hebt een pointer naar class 1 op address $1000. Als je nu tegen de compiler zegt dat je integer c wilt vullen met 50 dan komt er ongeveer in pseudo machine code iets te staan als:

store $1000+5, #50

Als je nu tegen de compiler 'liegt' en zegt dat op address $1000 geen object van classe 1 staat, maar van classe 2, en je wilt vervolgens van classe 2 integer c vullen, dan gaat het in dit simpele geval goed. Er wordt namelijk precies dezelfde machine code voor gegenereerd. IHA heb je deze garantie echter niet.

Als je nu een pointer (in java) naar een interface zou casten, dan genereerd de compiler precies die code alsof het object op die plaats in het geheugen -wel- die interface had geimplementeerd. -Als- de layout en vtable (of java's equivalent daarvan) precies overeenkomen dan gaat dat dus goed, anders gaat het gruwelijk fout. C en C++ programmeurs nemen soms deze verandwoordelijkheid.
De compiler kan dit echter niet controleren, dus is het niet toegestaan in Java. In java mag je niet rommelen met pointers. Daarom stelde ik ook dat enkel conceptueel de reinterpret_cast precies zou doen wij jij wilde. Uit .oisyn's post van Thursday 17 June 2004 18:05 blijkt dat dat ook inderdaad zo is.
Je zegt nu precies wat ik stelde in mijn reactie op jou... :)
[...]

Functioneel gezien is het een safe cast, maar practisch gezien hoeft dat helemaal niet zo te zijn. -Alleen- als de compiler voor de interface en het object dezelfde vtable genereerd zou het werken. Dit valt echter buiten de language spec, en is dus undefined behaviour. Als het op jouw compiler werkt is dat toevallig.
Volgens mij werkt de JVM niet zo low-level, aangezien er in de byte-code toch geen expliciete pointers voor komen, zal hij alles dynamisch moeten alloceren.

Maar de objecten zijn dus feitelijk identiek qua memory layout (want hun types zijn dat ook), alleen de offsets in het geheugen niet. Maar aangezien een cast over types gaat, zou dat niet uit moeten maken.
Oh, voor als je niet weet wat een vtable is, heel simpel gezegd: een array met verwijzingen naar functies die runtime (achter de schermen) doorlopen wordt om mbt polymorfisme de juiste functie implementatie te vinden.
Hmm, zegt me vrij weinig, aangezien ik de context van C++ niet ken (die linking en die scrupules met entry points van libraries etc. vormen juist mijn grote afkeer van C++ ;)).
[...]

Het heeft ook niks te maken met of C++ of Java hetzelfde zijn, of compatible of niet, het gaat om de concepten.
Daar spreek ik standaard over. :+
Ook in java in conceptueel gezien een interface inheritance. Ook in java heb je pointers. Sterker nog, je hebt in java alleen maar heap gealloceerde objecten, en dus alleen maar pointers. Java heeft ook geen call bij reference semantics, maar alleen call by value: pointers worden by value doorgegeven, etc, etc. Dat de dingen anders heten betekent niet dat de concepten verschillen.
Jaa, maar dat klopt ook wel, echter Java staat mij niet toe daarmee te tamperen, dus ik heb weinig aan het concept. :+
[...]

Heeft deze comment nou betrekking op mijn code sample of op jouw code? Wat ik opschreef is gewoon standaard java hoor. Als je een pointer naar een base hebt in Java kun je gewoon naar een van de feitelijke types casten.
Op jouw code, maar ik ken al die types dus niet compile-time, dat is het punt.
Hier komt al om de hoek kijken dat een interface implementen hetzelde is als inheritance, want via de instanceof operator en de cast maakt Java geen enkel onderscheid tussen beiden.

Bv

Java:
1
2
3
4
5
if (base instanceof ISomething)
    // ....

if (base instanceof Sub)
   // ....


Tevens je instantieert ook hier niet een interface: je maakt een instantance van een class (dat kun je, had je eerder gezegd), en die instance cast je naar het type van de interface.
Nu je het zegt, dit zou dan inderdaad moeten kunnen. Echter, probleempje: ik kan niet casten naar een Class(Type)-object, alleen naar een class (type). :p
[...]


Dat is wel het allerbelangrijkst, en in een van mijn eerste posts in deze thread had ik je ook al hierna gevraagt (maar je gaf geen antwoord hierop). Echter, -waar- is het type van de Interface onbekend?
Overal buiten de scope van de interface zelf.
Iniedergeval dus op de plek waar je class de interface zou moeten implementeren, maar ook op de plek waar je de ingelade code gaat gebruiken?
Juist. Ik denk dat er een misverstand onstaan is, ik laad die Classes dus niet voor m'n lol met die ClassLoader, anders had ik uiteraard wel met dat casten ed aan de gang gegaan. Zoals ik al zei: ik doe al mijn imports met die ClassLoader, op de standaard Java libraries na. Ik weet dat dit niet erg goed is voor de performance, maar de truuk is dat deze classes op zich (kunnen) staan, en ik dus vrijwel geen invoke()s ed hoef te doen via Java reflection op de instantie(s) van deze classes.
Er zal toch ooit ergens in de code een plek moeten zijn waar iemand de interface wel kent. Stel namelijk dat in de gehele code base nergens de interface bekend is, dus niet in de classes die je dynamisch laadt als plug-in, en niet in de code die dat laden uitvoert, dan heb je toch ook nergens die interface nodig?
Hehe, dat is al eerder ter sprake gekomen, dat is dus wel zo, want ik ken die interface dus wel, en ik weet dat ik hem ergens wil gebruiken. :)
Nou, duidelijk is dat dus niet zo, dus er komt ergens een plek die de interface wel kent. Nou, op dat moment kun je dus die denkbeeldige java reinterpret_cast doen.
Helaas... :'(
[...]


Check net pas je profiel en blijkt dus student HBO-IN te zijn. Kwa vraagstelling enzo zat ik eigenlijk aan een student van de universiteit nijmegen te denken :)
offtopic:
Laat ik nou nét van plan zijn daar te gaan studeren. /-\o_ :D /-\o_

Maar in welk opzicht? Als men zich daar in de regel ook niet blind staart op de meest voor de hand liggende mogelijkheden van bestaande programmeertalen dan komt mij dat goed uit... B)

[ Voor 3% gewijzigd door Verwijderd op 17-06-2004 21:46 ]


Verwijderd

Verwijderd schreef op 17 juni 2004 @ 21:40:
[...]

Wel, maar ik accepteer het niet. ;)
En ik ga niet roepen dat ik dat zelf maar aan ga passen oid (in een of andere high-level taal oid), omdat ik dat mogelijk (:P) niet kan, en omdat dat raar over komt.
Sommige concepten, zoals memory layout en eigenlijk het hele imperatieve model komen gewoon rechtstreeks voort uit de opbouw van de machine. Java wordt in 99% van de gevallen naar dezelfde machine gecompileert; de JVM. Deze is weliswaar meestal virtueel, maar volgt nog steeds het Von Neumann model. Het mapt dan ook redelijk naar de huidige computer architecturen. Soms zelfs een beetje -te- direct. In de JVM zijn variable reads en writes atomair, behalve voor Doubles. Dit vanwege mappings naar een echte machine.
Precies, dat begrijp ik ook wel, ik ben qua "machinale" talen een frequent beoefenaar van assembly. ;)
Juist ja... ergens geloof ik het niet helemaal ;)
[...]
Maar dat gaat niet op voor een "class" versus een "Class"...
Ik snap niet helemaal wat je met class vs Class bedoelt. Kwa data members geldt het echter voor alles wat maar een memory layout heeft.

In C++ kun je bv een object 'met de hand' in een leeg stukje geheugen opbouwen.

Bv, hier een vb. (kenners van de win32 API herkennen dit wel :) )

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BYTE* pData ;
RGNDATA* pRgnData ;
RECT* pRect ;
                    
// create RGNDATA structure 'manually'
pData = new BYTE[ sizeof( RGNDATAHEADER ) + sizeof( RECT ) * iCount ];      
pRgnData = ( RGNDATA* )pData ;

// first element of RECT array
pRect = ( RECT* )( pData + sizeof( RGNDATAHEADER ) ) ;
                    
// set fields of header
pRgnData->rdh.dwSize    = sizeof( RGNDATAHEADER  ) ;
pRgnData->rdh.iType     = RDH_RECTANGLES ;
// ...
Dat snap ik, maar hoe wil je Java dat laten doen...
Ik zou het iniedergeval niet weten. Het was voornamelijk bedoelt als voorbeeld om er achter te komen wat je nu precies bedoelde. Het begint langzamerhand een beetje duidelijk te worden nu :)
Volgens mij werkt de JVM niet zo low-level, aangezien er in de byte-code toch geen expliciete pointers voor komen, zal hij alles dynamisch moeten alloceren.
Bytecode is redelijk assembly-like hoor, en werkt dus wel zeer zeker expliciet met 'pointers'. Om dit niveau worden dat echter geen pointer genoemt, maar valt het onder een addressing mode zoals bv Register deferred of indirect.
Maar de objecten zijn dus feitelijk identiek qua memory layout (want hun types zijn dat ook), alleen de offsets in het geheugen niet.
Als 2 classes dezelfde memory layout voorschrijven dan hebben objecten van die classes ook precies dezelfde offset tov het address van de pointer. Het bepalen van welke offset welke data member heeft IS namelijk wat de memory layout bepaalt. :)

In C++ werkt het overigens iets gecompliceerder, omdat je verschillende base classen kunt hebben, en er natuurlijk maar eentje op offset 0 van address waar de pointer naar verwijst kan beginnen.
Hmm, zegt me vrij weinig, aangezien ik de context van C++ niet ken (die linking en die scrupules met entry points van libraries etc. vormen juist mijn grote afkeer van C++ ;)).
Het heeft nix met entry points in libs te maken. Standaard C++ kent ook het begrip dynamic/shared library helemaal niet. Dat zijn altijd platform extensies.

De vtable zorgt ervoor dat je language runtime weet welke functie hij moet aanroepen voor een object. Voor gewone functies wordt namelijk altijd een vast geheugen address gegenereerd voor een bepaalde functie call. Echter, in het geval van Java of C++ virtual functions kun je compile-time dit address niet bepalen, omdat je niet het echte type van een object weet. Pas runtime weet je waar in de inheritance-chain je zit. Je vtable bevat pointers naar de juiste functies (dus naar die van een sub class, als het object at runtime een sub is ipv de base). Dit is het hele principe van polymorfisme: Een sub kunnen gebruiken waar een base verwacht wordt.
Overal buiten de scope van de interface zelf.
Ok, dat is duidelijk.

Je hebt dus dat interface type helemaal niet nodig O-)

Want, als niemand, maar dan ook echt helemaal niemand die interface kent, dan zal dus ook niemand hem verwachten en dus nodig hebben.

Wat je dus wilt is slechts die functies van het object aanroepen die ook in de interface voorkomen die alleen jij kent en de maker van het object. Maar dan heb je toch die hele interface definitie niet nodig en roep je 'gewoon' via reflection de methoden aan die jij hard uit je hoofd kent. Toch? :?
Laat ik nou nét van plan zijn daar te gaan studeren. /-\o_ :D /-\o_
Maar in welk opzicht?
In Nijmegen wordt functioneel programmeren als de 'normale' programmeer taal geleerd. Wat je bij alle andere universiteiten bij vakken als Inleiding Programmeren krijgt wordt in Nijmegen expliciet Imperatief Programmeren genoemt. Natuurlijk worden machine architectuur enzo wel bekeken, maar de nadruk zal er (denk ik) niet op liggen daar.

  • Eelis
  • Registratie: Januari 2003
  • Laatst online: 21-02-2015
.

[ Voor 106% gewijzigd door Eelis op 18-02-2015 20:01 ]


Verwijderd

Topicstarter
Verwijderd schreef op 18 juni 2004 @ 00:27:
[...]


Sommige concepten, zoals memory layout en eigenlijk het hele imperatieve model komen gewoon rechtstreeks voort uit de opbouw van de machine. Java wordt in 99% van de gevallen naar dezelfde machine gecompileert; de JVM. Deze is weliswaar meestal virtueel, maar volgt nog steeds het Von Neumann model. Het mapt dan ook redelijk naar de huidige computer architecturen. Soms zelfs een beetje -te- direct. In de JVM zijn variable reads en writes atomair, behalve voor Doubles. Dit vanwege mappings naar een echte machine.
OK, maar ik controleer die machine dus niet (volledig).
[...]


Juist ja... ergens geloof ik het niet helemaal ;)
Ik houd je niet tegen. ;)
[...]


Ik snap niet helemaal wat je met class vs Class bedoelt. Kwa data members geldt het echter voor alles wat maar een memory layout heeft.
Zie: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Class.html
In C++ kun je bv een object 'met de hand' in een leeg stukje geheugen opbouwen.

Bv, hier een vb. (kenners van de win32 API herkennen dit wel :) )

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BYTE* pData ;
RGNDATA* pRgnData ;
RECT* pRect ;
                    
// create RGNDATA structure 'manually'
pData = new BYTE[ sizeof( RGNDATAHEADER ) + sizeof( RECT ) * iCount ];      
pRgnData = ( RGNDATA* )pData ;

// first element of RECT array
pRect = ( RECT* )( pData + sizeof( RGNDATAHEADER ) ) ;
                    
// set fields of header
pRgnData->rdh.dwSize    = sizeof( RGNDATAHEADER  ) ;
pRgnData->rdh.iType     = RDH_RECTANGLES ;
// ...


[...]


Bytecode is redelijk assembly-like hoor, en werkt dus wel zeer zeker expliciet met 'pointers'. Om dit niveau worden dat echter geen pointer genoemt, maar valt het onder een addressing mode zoals bv Register deferred of indirect.
Hehe, ok, maar nogmaals... ik kan zo low-level niet komen (zonder vuile truuks tenminste ;)).
[...]


Als 2 classes dezelfde memory layout voorschrijven dan hebben objecten van die classes ook precies dezelfde offset tov het address van de pointer. Het bepalen van welke offset welke data member heeft IS namelijk wat de memory layout bepaalt. :)
Dat maakt de offsets echter nog niet gelijk. ;)
Dat kan natuurlijk ook helemaal niet... maar aangezien ik het type niet ken, is dat vrij vervelend.
In C++ werkt het overigens iets gecompliceerder, omdat je verschillende base classen kunt hebben, en er natuurlijk maar eentje op offset 0 van address waar de pointer naar verwijst kan beginnen.
OK, maar dit is niet relevant voor Java... :P
[...]


Ok, dat is duidelijk.

Je hebt dus dat interface type helemaal niet nodig O-)

Want, als niemand, maar dan ook echt helemaal niemand die interface kent, dan zal dus ook niemand hem verwachten en dus nodig hebben.
Zoals ik al duidelijk heb proberen te maken is er een verschil tussen wat ik als programmeur zijnde ken, en wat de JVM kent.

Hoezo heeft niemand (geen enkele class bedoel je neem ik aan) hem nodig omdat hij hem niet kent (het type neem ik aan)? :?

De code is er volledig op toegespitst hoor, er is alleen nog maar een officiele implementation nodig, in feite dus een daadwerkelijke inheritance van de interface tav mijn subclass.
Wat je dus wilt is slechts die functies van het object aanroepen die ook in de interface voorkomen die alleen jij kent en de maker van het object. Maar dan heb je toch die hele interface definitie niet nodig en roep je 'gewoon' via reflection de methoden aan die jij hard uit je hoofd kent. Toch? :?
Ik kan geen methoden uit een interface aanroepen, aangezien deze geen daadwerkelijke code bevatten (zoals je weet). Ik zal de class dus moeten inheriten, oftewel de interface implementen.

Ik wil via die interface die implementors op de hoogte houden van een soort van events, lijkt me gesneden koek.

Maar ik heb al gezegd dat er geen praktisch probleem meer is, dus er vált niets op te lossen. (15e keer dat ik het zeg denk ik :P)
[...]


In Nijmegen wordt functioneel programmeren als de 'normale' programmeer taal geleerd. Wat je bij alle andere universiteiten bij vakken als Inleiding Programmeren krijgt wordt in Nijmegen expliciet Imperatief Programmeren genoemt. Natuurlijk worden machine architectuur enzo wel bekeken, maar de nadruk zal er (denk ik) niet op liggen daar.
Zoals het hoort. _/-\o_

Maar dat ligt er denk ik ook aan welke studie je gaat volgen. Als je technische informatica oid wil gaan doen heb je momenteel weer meer aan imperatieve talen.

Verwijderd

offtopic:
[quote]Eelis schreef op 18 juni 2004 @ 03:15:
Dit was misschien vroeger zo, maar nu niet meer. Ik studeer Informatica in Nijmegen, heb het eerste jaar er nu bijna op zitten, en ben (op school) nog niet geintroduceerd tot functionele programmeertalen. Voor de programmeervakken wordt in het eerste jaar voornamelijk C++ gebruikt.[/quote]

Interesant, maar het zat er natuurlijk wel in, je kunt zo'n starre houding niet vol blijven houden. Ik begreep dat Nijmeegse studenten ook een slechte naam begonnen te krijgen, zo van: "Oh iemand uit Nijmegen, waardeloos, die wil alles in clean gaan maken". Mischien onterecht, maar toch...

Verwijderd

Verwijderd schreef op 18 juni 2004 @ 18:04:
Zoals ik al duidelijk heb proberen te maken is er een verschil tussen wat ik als programmeur zijnde ken, en wat de JVM kent.

Hoezo heeft niemand (geen enkele class bedoel je neem ik aan) hem nodig omdat hij hem niet kent (het type neem ik aan)? :?
Dat is heel simpel. Als er in geen enkel stukje code, waar dan ook, in welke package dan ook, in een static function of niet, dynamisch ingeladen of niet, eventueel dynamisch gegeneerd (door een java source file te genereren en te compilen) enz enz... een verwijzing naar het type staat, dan is dat type gewoon niet nodig.

Ik bedoel dus niet of het type in de code resolved is (gevonden kan worden), maar gewoon of er een verwijzing naar staat. Nou, als dat NERGENS zo is, dan is er dus absoluut geen enkele denkbare situatie waar je het object toch als het type van je onbekende interface wilt hebben.

Bv

Java:
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
public interface IUnknown { // onbekende interface die alleen cynarite kent
    public int doIt();
}

public class UnknownImpl { /* class die IUnknown zou moeten implementen, maar wat helaas niet kan */ 
    public int doIt() { return 1;}
}

// code

public class SomeClass {

    public int someFunc () {

        //  laad IUnknownImpl dynamisch op welke manier dan ook, bv:
        Class myUnKnownImpl = Class.forName("UnknownImpl");

        // ... other code  

    }
}

// code in een functie in SomeClass, of andere class, dynamisch geladen, andere package, andere computer, whatever...

public void needIUnknown ( IUnknown unknown ) {
    // ...
    unknown.doIt();

}


Als je goed naar deze code kijkt, dan zie je dat er een functie is die een IUnknown verwacht. Dat is de reden dat je je geinstantieerde UnknownImpl class als een IUnknown wilt hebben. Als nergens in alle code bij elkaar een IUnknown nodig is dan wordt die dus niet gebruikt, en kan ie weggelaten worden.

Je kunt wel via reflection methodes aan willen roepen op UnknownImpl, mischien zelfs wel precies die methodes die in IUnknown gedefineerd staan, maar een IUnknown pointer zelf heb je niet nodig. Per definitie niet, als de naam in je gehele source niet voorkomt en ook nooit voor zal komen in welke dynamische geladen code dan ook.

Bekijk het eens andersom:

Je hebt een object van het type UnknownImpl, en met veel pijn en moeite heb je eindelijk er een IUnknown van kunnen maken. Wat dan? Wat kun je dan wat je eerst niet kon? Je kan het object niet doorgeven aan een functie die IUnknown verwacht, want je stelde zelf al dat die niet bestond. Wil je mischien de enigste functie doIt() gaan aanroepen? Maar dat kon ook al voordat je object als IUnknown gezien werd, namelijk UnknownImpl heeft precies die functie.

Bekijk het nog eens anders:

Ik voeg aan een bestaand Java project de interface "DitIsEenRareInterface" toe. Geen enkele code in het hele project kent en gebruikt deze interface. Ik zelf overigens wel, en diegene die de code schreef kent de interface ook, maar in geen enkel statement of function signature of wat dan ook komt de naam "DitIsEenRareInterface" voor. Wat is het nut van deze interface?
Ik wil via die interface die implementors op de hoogte houden van een soort van events, lijkt me gesneden koek.
Maar dan is er toch wel code die de interface gebruikt? :? :? :?
Als jij via die interface implementors wilt benaderen, dan gebruikt jou code toch die interface???
Maar ik heb al gezegd dat er geen praktisch probleem meer is, dus er vált niets op te lossen. (15e keer dat ik het zeg denk ik :P)
Nou, laten we er dan nog een 16de keer van maken ;)



Er is geen practisch probleem meer, deze discussie is puur theoretisch!



Zo, als ze het nu nog niet weten! :+

[ Voor 3% gewijzigd door Verwijderd op 18-06-2004 21:26 ]


Verwijderd

*lach* Ik geloof dat iedereen het nu maar opgegeven heeft?

Er bleek toch op het laatst dat er echt geen touw meer aan vast te knopen viel. Eerlijk gezegd is me nu toch nog steeds niet duidelijk wat de TS nu precies bedoelde.

Verwijderd

Topicstarter
Zoals ik al zei heb ik een aantal werkzaamheden met een wat hogere prioriteit op het moment, de vakantie staat voor de deur en dus kijk ik er ASAP naar.

Verwijderd

Topicstarter
Zo, mijn vakantie is aangebroken, ik heb eens de tijd genomen om serieus op je post in te gaan. :)
Verwijderd schreef op 18 juni 2004 @ 21:23:
[...]


Dat is heel simpel. Als er in geen enkel stukje code, waar dan ook, in welke package dan ook, in een static function of niet, dynamisch ingeladen of niet, eventueel dynamisch gegeneerd (door een java source file te genereren en te compilen) enz enz... een verwijzing naar het type staat, dan is dat type gewoon niet nodig.

Ik bedoel dus niet of het type in de code resolved is (gevonden kan worden), maar gewoon of er een verwijzing naar staat. Nou, als dat NERGENS zo is, dan is er dus absoluut geen enkele denkbare situatie waar je het object toch als het type van je onbekende interface wilt hebben.
Ik zie niet in hoe je tot die conclusie komt...
Er staat dus wél een verwijzing, aangezien ik deze Interface wil implementen, maar helaas mag die verwijzing er niet staan (ivm correctheid syntax Java).
Bv

Java:
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
public interface IUnknown { // onbekende interface die alleen cynarite kent
    public int doIt();
}

public class UnknownImpl { /* class die IUnknown zou moeten implementen, maar wat helaas niet kan */ 
    public int doIt() { return 1;}
}

// code

public class SomeClass {

    public int someFunc () {

        //  laad IUnknownImpl dynamisch op welke manier dan ook, bv:
        Class myUnKnownImpl = Class.forName("UnknownImpl");

        // ... other code  

    }
}

// code in een functie in SomeClass, of andere class, dynamisch geladen, andere package, andere computer, whatever...

public void needIUnknown ( IUnknown unknown ) {
    // ...
    unknown.doIt();

}


Als je goed naar deze code kijkt, dan zie je dat er een functie is die een IUnknown verwacht. Dat is de reden dat je je geinstantieerde UnknownImpl class als een IUnknown wilt hebben. Als nergens in alle code bij elkaar een IUnknown nodig is dan wordt die dus niet gebruikt, en kan ie weggelaten worden.
Maar hoe kom je er bij dat IUnknown nergens in alle code bij elkaar nodig is? :?

Nogmaals, ik laad geen class in die zelf al IUnknown implement, ik heb zelf een class (als code) die ik zelf IUnknown wil laten implementen.
Je kunt wel via reflection methodes aan willen roepen op UnknownImpl, mischien zelfs wel precies die methodes die in IUnknown gedefineerd staan, maar een IUnknown pointer zelf heb je niet nodig. Per definitie niet, als de naam in je gehele source niet voorkomt en ook nooit voor zal komen in welke dynamische geladen code dan ook.
Ik schrijf dus zelf UnknownImpl, zoals ik duidelijk heb vermeld. Dus, de naam komt wel voor, alhoewel dus de vraag is of dat de manier is om mijn doel te bereiken aangezien dit niet mogelijk lijkt.
Bekijk het eens andersom:

Je hebt een object van het type UnknownImpl, en met veel pijn en moeite heb je eindelijk er een IUnknown van kunnen maken. Wat dan? Wat kun je dan wat je eerst niet kon?
Dat is al helemaal geenszins wat ik wil\zeg. :D
Je kan het object niet doorgeven aan een functie die IUnknown verwacht, want je stelde zelf al dat die niet bestond. Wil je mischien de enigste functie doIt() gaan aanroepen? Maar dat kon ook al voordat je object als IUnknown gezien werd, namelijk UnknownImpl heeft precies die functie.
Hehe, dat begrijp ik wel, maar je laat nu wel je fantasie de vrije loop, dit is (idd) niet waar ik het over heb. Maar bedankt voor je uiteenzetting. _O_
Bekijk het nog eens anders:

Ik voeg aan een bestaand Java project de interface "DitIsEenRareInterface" toe. Geen enkele code in het hele project kent en gebruikt deze interface. Ik zelf overigens wel, en diegene die de code schreef kent de interface ook, maar in geen enkel statement of function signature of wat dan ook komt de naam "DitIsEenRareInterface" voor. Wat is het nut van deze interface?
Dat is er niet, maar ik stel duidelijk dat ik deze Interface wél wil gebruiken. Dit kan alleen niet als ik het type niet ken, zo krijg ik de indruk.

Is toch zo klaar als een klontje?
[...]


Maar dan is er toch wel code die de interface gebruikt? :? :? :?
Als jij via die interface implementors wilt benaderen, dan gebruikt jou code toch die interface???
Precies. Waar ontken ik dat dan? :?
[...]


Nou, laten we er dan nog een 16de keer van maken ;)



Er is geen practisch probleem meer, deze discussie is puur theoretisch!



Zo, als ze het nu nog niet weten! :+
Na deze kick zal er wel weer een lading Spuit Elven binnen komen stormen... :P

Verwijderd

Niemand die nog een poging waagt? Waar zijn de helden van P&W gebleven?


.oisyn? alarmnummer? whoami?

Of denken jullie allemaal dit het een hopeloze queste is? :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 01 juli 2004 @ 11:10:
Niemand die nog een poging waagt? Waar zijn de helden van P&W gebleven?

.oisyn? alarmnummer? whoami?

Of denken jullie allemaal dit het een hopeloze queste is? :)
Ik vind de discussie iets te kunstmatig van aard en zie het nut er al lang niet meer van in. helaas zijn de laatste tijd de discussies op /14 ook weer zwaar naadje... dus.. tja..

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:11
Ik ben geen held.

https://fgheysels.github.io/


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

*whoami wordt al bang van een scsi-terminator* :P

Verwijderd

Kom kom. Niet te bescheiden ;)

Verwijderd

Topicstarter
Alarmnummer schreef op 01 juli 2004 @ 11:40:
[...]

Ik vind de discussie iets te kunstmatig van aard en zie het nut er al lang niet meer van in. helaas zijn de laatste tijd de discussies op /14 ook weer zwaar naadje... dus.. tja..
Als iets kunstmatig is is het niet meteen nutteloos. ;)

Ik ga die dynamic proxies eens uitproberen, alhoewel misfire dus ontkende dat dat zou werken.

Misschien is hij bereid om als 'held' op te treden? :? :D

Verwijderd

Verwijderd schreef op 02 juli 2004 @ 00:32:
[...]

Als iets kunstmatig is is het niet meteen nutteloos. ;)
Inderdaad. Sommige mensen willen juist alleen dingen oplossen die een practisch nut hebben, terwijl andere juist weer theoretische dingen willen onderzoeken. Zeker met het oog op nieuwe ontwikkelingen (in bv talen als Java of C++), is het interesant om mogelijke nieuwe styles of syntax te bespreken.

Alleen, hoewel jij stellig vindt van niet en telkens zegt dat wij beter moeten lezen, moet ik toch stellen dat jij echt heel slecht bent in het uitdrukken van een probleem. Ik heb zelf 3 jaar les gegeven in C++ en vaak hadden mensen de meest vreemde ideeen over wat mogelijk moest zijn in een programmeertaal. Ipv, meteen te zeggen, nee dat is fout, dat kan niet, enz, ging ik vaak de discussie aan. Vaak bleek er toch wel een logica in de (voor C++) foutieve gedachtengang te zitten. Ik ben zelf ook actief in het ontwikkelen van een nieuwe taal gebasseerd op 'alternatieve' concepten, dus theoretisch is voor mij wel interesant.

Maar mischien wordt ik te oud, of ben ik niet slim genoeg, maar eigenlijk snap ik nog steeds niet wat je nu wilt. :'(

Is er hier eigenlijk wel iemand die snapt wat onze vriend Cybarite nu eigenlijk bedoeld?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 02 juli 2004 @ 00:32:
Ik ga die dynamic proxies eens uitproberen, alhoewel misfire dus ontkende dat dat zou werken.
Wat ik een beetje vreemd vind is dat je 100% vertrouwen hebt in die ene reactie van misfire, terwijl je de meeste suggesties van onze kant mbt dynamic proxies een beetje links laat liggen.

Ik denk eerlijk gezegd dat misfire gewoon ongelijk heeft (dat wil zeggen, hij heeft je probleem verkeerd begrepen) en dat dynamics proxies je probleem uitstekend op kunnen lossen :)

[ Voor 6% gewijzigd door .oisyn op 05-07-2004 22:14 ]

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.


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Verwijderd schreef op 05 juli 2004 @ 21:52:
[...]
Inderdaad. Sommige mensen willen juist alleen dingen oplossen die een practisch nut hebben, terwijl andere juist weer theoretische dingen willen onderzoeken. Zeker met het oog op nieuwe ontwikkelingen (in bv talen als Java of C++), is het interesant om mogelijke nieuwe styles of syntax te bespreken.
Dat is zeker interessant, maar dit topic is eigelijk ook niet meer op dat nivo. Het gaat over een ongelovelijk gekunsteld probleem waarvan ik het nut van de oplossing niet inzie.
Maar mischien wordt ik te oud, of ben ik niet slim genoeg, maar eigenlijk snap ik nog steeds niet wat je nu wilt. :'(
Ik hou het op je leeftijd ;) *nu maar hopen dat jij ouder ben dan ik*

*snapt het zelf ook al lang niet meer*

Verwijderd

Topicstarter
Wat diepgravend weer. :7

@henk_DE_man:
.oisyn had m'n probleem het beste door. Het gaat er om dat je zelf geen dingen moet bijdenken als ik ze niet noem. Dat is geen verwijt, dat doet bijna iedereen, en ik vast ook.

Maar ik heb een paar keer letterlijk gezegd waar ik geinteresseerd (nee, géén probleem ;)) in ben, en dat in soms slechts een paar zinnen...
Dus dan denk ik dat het duidelijk zou moeten zijn...

Maar nogmaals, voor de duidelijkheid:
Opgesomd:
- Ik 'ken' de Interface, dwz: haar classname en gewoon de volledige code (dus ook methods etc.)
- Echter, ik kan deze niet importen
- Ik weet dus heel goed welke methods ik dien te implementen, ik heb in feite een aparte klasse die volledig functioneel is op één ding na: het ontbreekt hem aan een "implements" keyword met daarachter de Interface-naam.

Dus:
- Ik wil runtime aangeven dat die bewuste klasse die Interface moet implementen (ja, ik weet het, als je een method niet/onjuist implement is het "panic" in de VM aangezien je dit niet met de compiler kunt afvangen )
- Ik weet (natuurlijk, anders zou het wel onzinnig zijn) wel de naam van de Interface, en weet de .class file ook te vinden uiteraard.
@.oisyn:
Nou, aangezien zijn verhaal vrij logisch in elkaar zat, en niemand het heeft ontkend.
Dynamic proxies laat ik desondanks niet links liggen:
Ik ga die dynamic proxies eens uitproberen, alhoewel misfire dus ontkende dat dat zou werken.
@Alarmnummer:
Dat heb je al een paar keer gezegd, wat is je probleem daarmee? :?
En waarom heb je het nog steeds over een probleem/oplossing?
Anders vind ik het ook vrij irritant, telkens die overbodige constateringen.

Maar goed, slap gelul allemaal, je komt nooit toe aan de dingen die je wilt doen tijdens vakanties, binnenkort vetrek ik ook voor een tijdje, ik zal die aangedragen suggesties zeker uitproberen, want ik blijf het interessant vinden. :)

[ Voor 4% gewijzigd door Verwijderd op 05-07-2004 22:39 ]


Verwijderd

Alarmnummer schreef op 05 juli 2004 @ 22:10:

Ik hou het op je leeftijd ;) *nu maar hopen dat jij ouder ben dan ik*
Marginaal verschil. Ben 28, begin 1976 (moet maar eens mijn profiel updaten)
*snapt het zelf ook al lang niet meer*
Het vreemde is dat ik eerst het ene zeg en dan zegt hij dat dat ongeveer de bedoeling is, en dan zeg je later het zelfde in iets andere woorden en dan is dat opeens -helemaal- niet de bedoeling, vervolgens leg je de gevolgen neer van het feit dat dat ene niet de bedoeling is en dan is dat ook niet de bedoeling. 8)7

Maar goed, ik geef het officieel op. Veel geluk met je theoretische probleem cybarite! :) Laat je het nog weten als je de oplossing (zelfs al is deze theoretisch) gevonden hebt?

Verwijderd

Topicstarter
Verwijderd schreef op 05 juli 2004 @ 23:53:
[...]

Het vreemde is dat ik eerst het ene zeg en dan zegt hij dat dat ongeveer de bedoeling is, en dan zeg je later het zelfde in iets andere woorden en dan is dat opeens -helemaal- niet de bedoeling, vervolgens leg je de gevolgen neer van het feit dat dat ene niet de bedoeling is en dan is dat ook niet de bedoeling. 8)7
Ehm.. sorry hoor.. maar die samenvatting is een letterlijke kopie van wat ik al eerder postte. Dit was altijd het probleem, en ik heb nooit iets anders gezegd. :?
Maar goed, ik geef het officieel op. Veel geluk met je theoretische probleem cybarite! :) Laat je het nog weten als je de oplossing (zelfs al is deze theoretisch) gevonden hebt?
Het is in principe een doodnormale vraag...
Als niemand een to-the-point antwoord geeft/weet, dan wordt het wellicht een probleem ja. :+

Enfin, jij veel succes met je C++-hobby, iedereen heeft nou eenmaal andere interesses. :)

  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 05-11 10:11
omdat ik in de hele thread niets gelezen heb over spring wou ik dit nog es toevoegen...

Om het probleem van de TS op te lossen kan je perfect gebruik maken van Introductions in Spring.

je kan er via AOP nieuwe functionaliteit aan klassen geven @ runtime.

enkel voorbeelden waarbij je dit zou kunnen doen:
  • wijzigingen van object detecteren (uit Pro Spring boek):
    je wil detecteren of een object gewijzigd is of niet, om niet in elke methode te hoeven controleren of een object gewijzigd is schrijf je hiervoor een simpele Interface met een methode bv: isModified(). Als je dit voor elk object wil doen heb je veel redundante code, en eenmaal abstracte klasse maken verlies je de enige kans op overerving... hier dus ideaal voorbeeld voor icm met AOP (enkel methodes die state kunnen wijzigen hoeven we op te vangen)
  • Alarmnummer had ooit ergens een thread over immutable objecten, ik zou denken dat je hier ook wel wat mee kan aanvangen

"Live as if you were to die tomorrow. Learn as if you were to live forever"


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Hoe lost dat zijn probleem op dan :?

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.


  • Cuball
  • Registratie: Mei 2002
  • Laatst online: 05-11 10:11
sorry, ik had iets te snel over het probleem gelezen...

wat ik bedoel is dat je in feite met Spring, snel een klasse een nieuwe Interface kan laten implementeren zonder dat je dit in de code hoeft te doen

maar bij TS is deze zogezegd al geimplementeerd maar wil hij er dynamisch de implements aan toevoegen... denk niet dat dit mogelijk is met spring

"Live as if you were to die tomorrow. Learn as if you were to live forever"


Verwijderd

Grappig dat er weer posts zijn in de "mother of all vague threads" ;)

Spring kan idd veel declaratief doen, maar het probleem van de topic starter was eigenlijk meer dat hij het zelf niet wist wat nou precies het probleem was (of dat ik het gewoon niet begreep ;) ).

Met code generation en byte code injection kun je een heel eind komen als je aparte dingen wil doen. In directe JVM byte code is zelfs nog ietsje meer mogelijk dan je met alleen Java zelf kan. Maar het punt was dat de TS wilde dat een object run-time een interface kreeg toebedeeld, terwijl er geen enkel stukje code was wat die interface dan zou gaan aanroepen.

Na de hele thread nog eens doorgelezen te hebben, is het enigste wat ik me kan bedenken dat je de interface als een soort tag gebruikt voor andere reflection gebasseerde code.

In pseudo code

code:
1
2
3
4
5
dynamically inject interface "X" to object
...
in other reflection based code:
   check if object implements interface "X" using reflection
   call methods on object using reflection


Het aparte is dan dat de "other code" zowieso al de methods kon aanroepen via reflection, en dat tevens de methods die uiteindelijk worden aangeroepen door reflection nog niet eens perse diegene zijn die in de interface voorkomen. Je kunt je wel voorstellen dat de interface de methods aan gaat geven die (blind) opgeroepen gaan worden. Dit is enigzins vergelijkbaar met JUnit en een test suite, hoewel je daar geen interface voor hoeft te injecteren.

Bijvoorbeeld (pseudo weer)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Interface X
   getA()
   getB()   

Object Y   
   getA()
   getB()
   getC()

dynamically inject interface "X" to object Y
...
in other reflection based code:
   check if object implements interface "X" using reflection
   read interface "X" specification
   for all methods i found in specification
      call method i on object using reflection

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
.oisyn schreef op maandag 05 juli 2004 @ 22:09:
[...]
Wat ik een beetje vreemd vind is dat je 100% vertrouwen hebt in die ene reactie van misfire, terwijl je de meeste suggesties van onze kant mbt dynamic proxies een beetje links laat liggen.

Ik denk eerlijk gezegd dat misfire gewoon ongelijk heeft (dat wil zeggen, hij heeft je probleem verkeerd begrepen) en dat dynamics proxies je probleem uitstekend op kunnen lossen :)
Ik sluit helemaal niet uit dat ik het probleem niet correct snapte in mijn oorspronkelijke reactie en de oplossingen die ik toen gaf. Ik heb in die reactie ook aangegeven dat ik graag wilde dat de TS zijn probleemstelling verder zou toelichten.

Mijn samenvatting van de probleemstelling in de openingspost luidt als volgt:

1. Maak een instantie aan van een klasse X.
2. Wijs de instantie van klasse X toe aan een variabele van een bepaald Interface Y, wat echter niet door klasse X wordt geïmplementeerd.

Volgens mij los je dat niet op met dynamic proxies. (Dynamic) Proxies worden typisch gebruikt om bepaalde pass-through functionaliteit te implementeren om vervolgens een object met dezelfde interface te invokeren, niet om een mapping te maken tussen twee verschillende types. Technisch kan het wel (je kunt alles met dynamic proxies doen), alleen is het mechanisme daar niet voor bedoeld.

Als je zelf at compile time zou weten dat een bepaalde mapping nodig is, dan zou je dat volgens het Adapter patroon met een hulp-object op willen lossen, waarin een expliciete mapping tussen interface Y en klasse X is geïmplementeerd.

Wil je het at runtime doen en je wilt de bovenstaande probleemdefinitie letterlijk oplossen, dan zul je een vorm van bytecode modificatie toe moeten passen. De suggestie van Spring is in dit geval helemaal niet zo vreemd, want het AOP mechanisme van Spring maakt dit soort modificaties ook mogelijk.

Over de eerdere reactie dat een interface en een abstracte klasse gelijk zijn als de abstracte klasse alleen abstracte definities bevat, heb je praktisch gezien gelijk. Maar dat wil niet zeggen dat ik ongelijk heb als ik zeg dat de definitie van het begrip interface anders is dan de definitie van het begrip abstracte klasse. In Brabant hebben we een gezegde: "Als mijn tante een snor had dan was ze mijn oom." Vrij vertaald betekent het zoiets dat het woordje "als" veel verschil uit kan maken. :)

Verwijderd

Geen idee of je dit bedoelt.. maar ik zag het stukje over je interface en classe laden met pluginloader... die gebruik ik ook ! Misschien dat jij er wat aan hebt :)

[rml][ JAVA] ClassCastException bij dynamisch laden classes.[/rml]

Verwijderd

In het licht van deze discussie is het volgende mischien nuttig om te lezen. Dit artikel gaat over precies dit onderwerp:

http://www.coconut-palm-s...itor/2005/04/29#duck_type

Het wordt hier duck typing genoemd.

Een quote uit het artikeltje:
This is exactly what Duck Typing allows us to do—to implement an interface at runtime. So all that remains is to figure out a way to implement this in Java.

In other words, we want to be able to rewrite our constructor to read something like this:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
    public ImageMgr(Object receiver, Image image) {
        if (!DuckType.instanceOf(IImageHolder.class, receiver)) {
            throw new ClassCastException("Cannot implement IImageHolder");
        }

        this.image = image;

    IImageHolder imageHolder = (IImageHolder)
            DuckType.implement(IImageHolder.class, receiver);
    imageHolder.setImage(image);
    imageHolder.addDisposeListener(this);
    }
Pagina: 1 2 Laatste