[alg] Nut van overerving in static classes

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

Acties:
  • 0 Henk 'm!

  • netvor
  • Registratie: September 2000
  • Laatst online: 08-04-2024
Dit topic is afgesplitst van [alg] Slechtste programmeervoorbeelden deel 2


Dat dacht ik zelf ook. Even voor de duidelijkheid, het was dus de bedoeling dat dit soort functies als
static worden gedeclareerd?

Over static gesproken, ik was laatst voor een schoolopdracht iets aan het coden (in Java), netjes OOP met abstract classes, en kwam tot het punt waarbij ik graag een arbstract static method in die class wilde stoppen.

Een half uur, een paar compiler errors en wat gegoogle later kwam ik tot de wonderbaarlijke ontdekking dat de architectuur van Java geen methods toelaat die 'abstract static' zijn. En het ergste is nog wel dat dit volgens Sun geen bug is, maar een feature. :|

OK, ok, ik snap de achterliggende gedachte enzo waarom abstract static niet mag, maar ik vind het nog steeds gebrekkig. Het ontbreken van multiple inheritance hebben ze (min of meer) opgevangen met interfaces, maar de mensen die abstract static methods willen laten ze in de kou. ;(

[ Voor 6% gewijzigd door Janoz op 16-05-2007 11:58 ]

Computer Science: describing our world with boxes and arrows.


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
netvor schreef op maandag 14 mei 2007 @ 16:30:
Een half uur, een paar compiler errors en wat gegoogle later kwam ik tot de wonderbaarlijke ontdekking dat de architectuur van Java geen methods toelaat die 'abstract static' zijn. En het ergste is nog wel dat dit volgens Sun geen bug is, maar een feature. :|
Realiseer je wel dat static methods class methods zijn en dus niets op object (instantie) niveau kunnen doen, dus ook geen overerving. Meestal worden static methods ook al compiletime geresolved, geen idee hoe Java dat doet overigens.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

netvor schreef op maandag 14 mei 2007 @ 16:30:
OK, ok, ik snap de achterliggende gedachte enzo waarom abstract static niet mag, maar ik vind het nog steeds gebrekkig. Het ontbreken van multiple inheritance hebben ze (min of meer) opgevangen met interfaces, maar de mensen die abstract static methods willen laten ze in de kou. ;(
Volgens mij snap je helemaal niet waarom het niet mag, anders kwam je niet met bovenstaande alinea :). Het is ook niet dat het niet mag, het is dat het gewoon niet kan. Hoe had je je dat voorgesteld dan? Een abstract method in een class betekent dat je die class niet mag instantieren, en wil je een subclass instantieerbaar maken dan moet je die abstract method implementeren. Static methods werken niet op een instantie, dus daar hoeft sowieso niet voor geinstantieerd te worden. En andersom hoeft een derived class 'm niet te implementeren om instantieerbaar te zijn, want het heeft wederom niets met instanties te maken.

Een abstract static method zou je dus ook nooit aan kunnen roepen, want er is nooit een implementatie in een derived class die eraan gelinkt wordt - je roept 'm immers aan op de base, en er is geen runtime type om de implementatie bij op te zoeken (want: geen instantie). Hij blijft derhalve altijd abstract en nooit aanroepbaar.

Abstract static is dus een nutteloos concept, en ik kan me geen enkele situatie indenken waar je het voor nodig zou hebben.

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.


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 02-06 17:35

MBV

Ik kan me voorstellen dat je het wilt hebben voor een standaard-implementatie van Singleton, of parameterized singleton (waarbij de get()-functie een argument heeft). Ik had er alleen niet aan gedacht dat je dat niet kan implementeren, maar het idee is wel logisch :)

Acties:
  • 0 Henk 'm!

  • netvor
  • Registratie: September 2000
  • Laatst online: 08-04-2024
PrisonerOfPain schreef op maandag 14 mei 2007 @ 16:43:
Realiseer je wel dat static methods class methods zijn en dus niets op object (instantie) niveau kunnen doen, dus ook geen overerving. Meestal worden static methods ook al compiletime geresolved, geen idee hoe Java dat doet overigens.
Dat het in Java niet kan accepteer ik. Maar wat ik niet accepteer is de mening dat het ook echt niet anders zou kunnen. OK, een static method is een class method, ben ik het mee eens. Maar waarom zou inheritance alleen op object niveau geregeld moeten worden? Waarom worden static fields en methods daarvan uitgesloten? Ik gaan hier geen goede reden voor zien.

Static methods worden op twee manieren aangeroepen: (1) rechtstreeks, met toevoeging van de class name: in dit geval gebruiken we de implementatie van die class, of de dichtstbijzijnde parent class die een implementatie heeft; (2) vanuit objects: in dit geval gebruiken we dan de implementatie van de class waarvan dit object een instantie is (of de dichtsbijzijnde parent class die een implementatie heeft).

Dit scenario wordt AFAIK gebruikt in Smalltalk, en Smalltalk is de oorzaak dat ik naar static abstract in Java ging verlangen.
Maar zoals gezegd, Java resolved static calls bij het compileren en dat gooit roet in het eten. Dus ik blijf erbij dat het een beperking van Java is :-)

Maar beperking of geen beperking, Java is een 100% prettigere taal om in te werken dan het gedrocht dat Smalltalk heet.

Computer Science: describing our world with boxes and arrows.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

netvor schreef op dinsdag 15 mei 2007 @ 01:22:
Static methods worden op twee manieren aangeroepen: (1) rechtstreeks, met toevoeging van de class name: in dit geval gebruiken we de implementatie van die class, of de dichtstbijzijnde parent class die een implementatie heeft;
Zoals reguliere static methods in Java dus.
(2) vanuit objects: in dit geval gebruiken we dan de implementatie van de class waarvan dit object een instantie is (of de dichtsbijzijnde parent class die een implementatie heeft).
Wat dus weer gewoon kan met een non-static method.

Als ik het goed begrijp is het enige wat jij wil dus syntactische suiker waarbij je een static method definieert, waarvan automatisch een non-static proxy wordt gemaakt die de static methode aanroept?

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Base
{
    abstract void func();
}

class Derived1 extends Base
{
    static void funcS() { System.out.println("Derived1"); }
    void func() { funcS(); }
}

class Derived2 extends Base
{
    static void func() { System.out.println("Derived2"); }
    void func() { funcS(); }
}


waarbij func() en funcS() eigenlijk dezelfde naam hebben, wat niet kan in Java.

Wat zou hier een nuttige use-case voor zijn?

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.


Acties:
  • 0 Henk 'm!

  • MBV
  • Registratie: Februari 2002
  • Laatst online: 02-06 17:35

MBV

singleton, waarbij de get() functie overridden wordt?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zodat je die ene instantie nodig hebt om de overridden get() functie op aan te roepen, wat dus niet meer hoeft omdat je die ene instantie al hebt? :)

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.


Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
.oisyn schreef op maandag 14 mei 2007 @ 16:53:
[...]
Abstract static is dus een nutteloos concept, en ik kan me geen enkele situatie indenken waar je het voor nodig zou hebben.
Ik denk dat er wel degelijk een nuttige usecase te bedenken is (voor het overiden van static methods in het algemeen).

Stel je voor dat je een class hebt met static methods om een message naar een one & only resource te sturen. Deze methods kun je een message key meegeven. De provider van die resource heeft een handige default class voor je gemaakt:

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
public class OneAndOnlyResourceMessenger {

   static public void sendMessage( int userID, String key, Object ... parameters ) {
      // Do complicated stuff first with ID
      // [ ... code here...]

      // Finally send the message
      SomeFactory.getOneAndOnlyResource(userID).send( getMsgString(key, parameters ) );
   }

   static public String getMsgString(String key, Object... parameters) {
        // Get Locale in some way
        Locale locale = Context.getLocale();
        
         // Get resource bundle in some way
        ResourceBundle bundle = Context.getBundle();
        
        // Get msg
        String msg = bundle.getString(key);
        
        // Format msg
        // ... etc
        
        return msg; 
   }
}


Stel nu dat ik een application specific manier heb om aan de hand van de key de message key te verkrijgen. De standaard OO aanpak is om een subclass te maken, en getMsgString te overriden:

Java:
1
2
3
4
5
6
public class MyOneAndOnlyResourceMessenger extends OneAndOnlyResourceMessenger {

   static public String getMsgString(String key, Object... parameters) {
      // Resolve key in some app specific way
   }
}


In usercode gebruik ik dan:

Java:
1
2
3
   
   // Looks nice, but doesn't work: still uses OneAndOnlyResourceMessenger.getMsgString
   MyOneAndOnlyResourceMessenger.sendMessage( 100, "System.err.connectionFailure", 10, 100 );


Natuurlijk werkt bovenstaande niet in Java. Ondanks dat ik de MyOneAndOnlyResourceMessenger class name gebruik om sendMessage aan te roepen, is de binding naar de getMsgString method altijd naar de implementatie in OneAndOnlyResourceMessenger (invokeStatic).

In theorie zou er (IMHO) best een bytecode kunnen zijn (invokeVirtualStatic?) die naar de class name kijkt waarop de method call gemaakt werd, en daar eerst zoekt naar een implementatie.

Omdat polymorfisme nog niet eens van toepassing is en de class name waarop de aanroep plaats vind compile-time bekend is, kan de compiler ook invokeStatic blijven gebruiken, maar dan voor de super class een nieuwe class genereren waarbij de juiste method name al compile time ingevuld. Dat laatste is niet helemaal conventioneel en er zitten vast wel wat haken en ogen aan ;)

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

Anoniem: 201130

flowerp schreef op dinsdag 15 mei 2007 @ 21:36:
[...]


Ik denk dat er wel degelijk een nuttige usecase te bedenken is (voor het overiden van static methods in het algemeen).

Stel je voor dat je een class hebt met static methods om een message naar een one & only resource te sturen. Deze methods kun je een message key meegeven. De provider van die resource heeft een handige default class voor je gemaakt:

Java:
1
2
3
4
5
6
7
public class OneAndOnlyResourceMessenger {

   static public void sendMessage( int userID, String key, Object ... parameters ) {
   }
   static public String getMsgString(String key, Object... parameters) {
   }
}
Ik heb even je code ingekort om wat duidelijk te maken met alleen de methode namen. Wat jij hier doet is namelijk een static class maken die eigenlijk niet static hoort te zijn. Beide methodes gebruiken namelijk dezelfde set parameters, waardoor een instance hier veel beter op zijn plaats is. Natuurlijk kan het met een static class, maar laten we eerlijk zijn... In principe uiteindelijk kun je alles static maken zolang je alle data maar als parameters blijft meegeven.

Daarnaast is dit natuurlijk eenvoudig op te lossen met een Singleton. Ik kan eigenlijk geen 1 situatie bedenken waarin ik bovenstaande voorbeeld niet kan omzeilen op een elegante(re) wijze.

In jouw voorbeeld zou je in de getMsgString methode overigens gewoon een factory pattern kunnen toepassen om het op te lossen in de huidige wijze.

[ Voor 5% gewijzigd door Anoniem: 201130 op 15-05-2007 21:49 . Reden: Factory pattern stukje toegevoegd. ]


Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
Anoniem: 201130 schreef op dinsdag 15 mei 2007 @ 21:48:
[...]
Wat jij hier doet is namelijk een static class maken die eigenlijk niet static hoort te zijn.
Beide methodes gebruiken namelijk dezelfde set parameters
Er zullen 100'en redenen zijn waarom deze class niet static moet zijn, maar ik geloof niet dat dat een goede reden is.
In principe uiteindelijk kun je alles static maken zolang je alle data maar als parameters blijft meegeven.
Nee hoor, dikwijls heb je gewoon state in een object. Veel functies zijn echter in principe stateless operaties en dan is het juist binnen een object instance beter om alles als parameter door te geven. Je kent ze vast wel die classes; 10 tallen members die als instance data gedeclareerd zijn, terwijl ze alleen ergens lokaal binnen in een method gebruikt worden. Je krijgt dan (bij grote classes) een soort situatie als met globale parameters; er is niet snel meer te zien welke functie op welke wijze wat beïnvloed. Bij het doorgeven als parameters is je dataflow veel beter te volgen en te analyseren.
Maar we dwalen af... ;)
In jouw voorbeeld zou je in de getMsgString methode overigens gewoon een factory pattern kunnen toepassen om het op te lossen in de huidige wijze.
Er zijn tal van alternatieven mogelijk. Je kunt ook een interface KeyResolver defineren, daar een instance van setten in een static member van je class, en de static method die laten gebruiken. Heb je ook een default implementatie die user code kan vervangen.

Dat is echter niet het punt waar het om ging.

De bovenstaande code liet zien dat static inheritance te gebruiken is, dat het niet een functie is waar je met geen mogelijkheid nuttige code mee kan maken.

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

En eigenlijk heb je dus de restrictie dat je van een class met een overridable static method maar 1 derived class mag maken? Want dit gaat uiteraard niet werken
Java:
1
2
3
4
5
6
7
8
9
10
11
class Base { abstract static void func(); }
class Derived1 extends Base { static void func() { } }
class Derived2 extends Base { static void func() { } }

class Main
{
    public static void main(String[] args)
    {
        Base.func(); // en nu?
    }
}


Een singleton is dan beter op z'n plaats. Bovendien heb je dan het voordeel dat er wel verschillende derived classes in je app mogen bestaan (je mag alleen maar van 1 een instantie hebben)

[ Voor 17% gewijzigd door .oisyn op 15-05-2007 23:52 ]

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.


Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
.oisyn schreef op dinsdag 15 mei 2007 @ 23:49:
En eigenlijk heb je dus de restrictie dat je van een class met een overridable static method maar 1 derived class mag maken? Want dit gaat uiteraard niet werken
Java:
1
2
3
4
5
6
7
8
9
10
11
class Base { abstract static void func(); }
class Derived1 extends Base { static void func() { } }
class Derived2 extends Base { static void func() { } }

class Main
{
    public static void main(String[] args)
    {
        Base.func(); // en nu?
    }
}
Volgens mij niet, want je gebruikt toch dit?


Java:
1
2
3
4
5
6
7
8
9
10
11
class Base { abstract static void func(); }
class Derived1 extends Base { static void func() { } }
class Derived2 extends Base { static void func() { } }

class Main
{
    public static void main(String[] args)
    {
        Derived1 .func(); // werkt! :)
    }
}


Maar dit laatste is flauw, want dat werkt nu al. Waar het om gaat is dat er een method in base is, die niet in Derived zit en op z'n beurt een method aanroept die wel in derived zit.

Dit werkt namelijk nu ook al:

Java:
1
2
3
4
5
6
7
8
9
10
class Base { static void func(); }
class Derived1 extends Base {  }

class Main
{
    public static void main(String[] args)
    {
        Derived1 .func(); // werkt! :)
    }
}


Dit werkt niet:

Java:
1
2
3
4
5
6
7
8
9
10
class Base { static void func(){func1();} static void func1(){} }
class Derived1 extends Base { static void func1(){} }

class Main
{
    public static void main(String[] args)
    {
        Derived1 .func(); // werkt, maar misschien niet wat we verwachten.
    }
}

[ Voor 29% gewijzigd door flowerp op 16-05-2007 00:09 ]

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

Allemaal leuk en aardig, maar wat probeer je nou aan te tonen? Dat als je een static methode aanroept op Derived1, er een derived type bekend is, zodat alle static methods van Base die je vanuit die context aanroept en die overriden zijn in Derived, dat dan die varianten worden gebruikt? Ik vind het maar een vage en onintuitieve situatie. Eigenlijk ben je dan bezig een static callback te creeren die vanuit de logic in Base aangeroepen wordt. En als dat dan ook de enige usecase is van een dergelijke "virtual" static method, die op vele andere manieren ook makkelijk te implementeren is (delegates, interfaces), waarom dan uberhaupt de moeite nemen om het te implementeren in een taal?

Het is imho hetzelfde als een speciale operator maken die iets met 25 vermenigvuldigt. Je hebt het zelden nodig, en als je het nodig hebt is het met al beschikbare functionaliteit ook triviaal om te implementeren.

[ Voor 30% gewijzigd door .oisyn op 16-05-2007 01:15 ]

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.


Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem


Acties:
  • 0 Henk 'm!

Anoniem: 201130

Wel een mooie korte bondige uitleg van jouw daar :P

Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
Wel vrij vreemd zeg dat dit zo'n gevoelig onderwerp blijkt te zijn. Inheritance heb je natuurlijk wel gewoon bij een static call. In het 2de voorbeeld wat ik geef in flowerp in "[alg] Nut van overerving in static class...", heeft Derived1 geen method func, maar inherit deze van Base.

Ook is een overide mogelijk. In diezelfde post, 1ste voorbeeld. heeft zowel Base als Derived1 de method func, en zal diegene in Derived1 worden aangeroepen.
.oisyn schreef op woensdag 16 mei 2007 @ 01:12:
Het is imho hetzelfde als een speciale operator maken die iets met 25 vermenigvuldigt. Je hebt het zelden nodig, en als je het nodig hebt is het met al beschikbare functionaliteit ook triviaal om te implementeren.
Ik weet het niet hoor. Dit is toch wel wat fundamenteler dan zo'n speciale operator. Uiteindelijk kun je alles wel met een minimale functionaliteit implementeren of omheen werken. Jij weet natuurlijk als geen ander dat alle taal constructies in C++ feitelijk overbodig zijn t.o.v. bijvoorbeeld C. Classes kun je gewoon zelf maken door structs en functie pointers te gebruiker, inheritence door een eigen vtable te implementeren, etc.

In deze situatie gaat het feitelijk nog niet eens om nieuwe syntax, het gaat om een regel.

Wel denk ik dat het een theoretische discussie blijft. Aan Java zelf kun je het natuurlijk eigenlijk nooit meer toevoegen; het veranderd stilletjes de betekenis van bestaande code, tenzij je verplicht om de @Overide annotation er mee te combineren.

(btw, ik ben niet perse een voorstander van zo'n 'invokeVirtualStatic' hoor, ik probeer alleen aan te geven dat er wel degelijk een gedachte achter kan zitten; dat het niet zomaar een kreet is van een beginner die de concepten niet snapt (zoals een final abstract method willen hebben ofzo).

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
Ik ben het eigenlijk wel met .oisyn eens. Daarnaast heb je alleen maar één abstract voorbeeld gegeven waarbij een abstract static methode handig zou kunnen zijn, maar ik zie niet een practisch voorbeeld waarbij ik dat ooit nodig zou hebben. Static functies heb ik sowieso niet zo heel vaak nodig en gebruik ik meestal alleen voor dingen als een singleton pattern of constante waardes (static final). Over het algemeen zou je alle functies die overerving vereisen toch op object-niveau willen hebben?

Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
Marcj schreef op donderdag 17 mei 2007 @ 12:19:
Ik ben het eigenlijk wel met .oisyn eens. Daarnaast heb je alleen maar één abstract voorbeeld gegeven waarbij een abstract static methode handig zou kunnen zijn
Het was een concreet voorbeeld en daarmee opzich al het tegenbewijs van de stelling dat er geen enkele nuttige usecase te bedenken was.

Natuurlijk is "nuttig" een persoonlijke kwalificatie ;)

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

Anoniem: 201130

flowerp schreef op donderdag 17 mei 2007 @ 16:10:
[...]


Het was een concreet voorbeeld en daarmee opzich al het tegenbewijs van de stelling dat er geen enkele nuttige usecase te bedenken was.

Natuurlijk is "nuttig" een persoonlijke kwalificatie ;)
Nee, het was een voorbeeld waar veel concretere alternatieven voor zijn, waardoor het tegenbewijs nog steeds niet geleverd is ;).

[ Voor 6% gewijzigd door Anoniem: 201130 op 17-05-2007 16:38 ]


Acties:
  • 0 Henk 'm!

  • Jrz
  • Registratie: Mei 2000
  • Laatst online: 06:29

Jrz

––––––––––––

<- zoekt even op TS naam in dat andere topic :Y)

Ennnnnnnnnn laat losssssssss.... https://github.com/jrz/container-shell (instant container met chroot op current directory)


Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
flowerp schreef op donderdag 17 mei 2007 @ 16:10:
[...]


Het was een concreet voorbeeld en daarmee opzich al het tegenbewijs van de stelling dat er geen enkele nuttige usecase te bedenken was.

Natuurlijk is "nuttig" een persoonlijke kwalificatie ;)
Het voorbeeld die je geeft is wel concreet, maar met abstracte namen (Base en Derived). Ik bedoel een echte situatie waarbij je dat zou gebruiken, want ik programmeer al 6 jaar in java, maar ben het echt nog nooit in een situatie beland waarbij ik dat nodig zou zijn. Overerving lijkt me dan ook iets voor Objecten ;). Daarom vroeg ik om een situatie waar je die constructie die je gaf nodig bent.

De enige situatie die ik me kan voorstellen is een volledig statische klasse (zodat er maar één van is), maar dit is natuurlijk ook met het Singleton pattern op te lossen.

Acties:
  • 0 Henk 'm!

Anoniem: 201130

Marcj schreef op donderdag 17 mei 2007 @ 17:14:
[...]

Het voorbeeld die je geeft is wel concreet, maar met abstracte namen (Base en Derived). Ik bedoel een echte situatie waarbij je dat zou gebruiken, want ik programmeer al 6 jaar in java, maar ben het echt nog nooit in een situatie beland waarbij ik dat nodig zou zijn. Overerving lijkt me dan ook iets voor Objecten ;). Daarom vroeg ik om een situatie waar je die constructie die je gaf nodig bent.

De enige situatie die ik me kan voorstellen is een volledig statische klasse (zodat er maar één van is), maar dit is natuurlijk ook met het Singleton pattern op te lossen.
Ik ben al weer vaker in dit soort situaties beland. Wij zijn toen eens goed naar ons design gaan kijken waarom we uberhaubt in deze situatie kwamen en kwamen toen er achter dat die static methodes die zou handig leken veel beter tot hun recht kwamen in instances of waar een singleton idd genoeg was.

Acties:
  • 0 Henk 'm!

  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Een static methode zou in feite gewoon een 'utility' methode moeten zijn (en omgekeerd). Oftewel ze doen alleen maar dezelfde acties op de gegeven invoerparameter(s). Dit soort methoden horen helemaal niet in een singleton. Maak de default constructeur van zo'n utilityklasse (een klasse met alleen maar static methoden) gewoon private.

Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
Marcj schreef op donderdag 17 mei 2007 @ 17:14:
[...]

Het voorbeeld die dat je geeft is wel concreet, maar met abstracte namen (Base en Derived).
Uhhmmm...

flowerp in "[alg] Nut van overerving in static class..."

De MyOneAndOnlyResourceMessenger die ik daar noemde was toch aardig concreet...

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

Anoniem: 201130

flowerp schreef op donderdag 17 mei 2007 @ 22:36:
[...]


Uhhmmm...

flowerp in "[alg] Nut van overerving in static class..."

De MyOneAndOnlyResourceMessenger die ik daar noemde was toch aardig concreet...
Er zijn 4 mensen die aangeven dat jouw voorbeeld lang niet zo concreet is en nauwelijks je punt bewijst en toch blijf je het beweren. Ook op het internet is weinig bijval te vinden voor jouw punt.

Kun jij nu eens goed uitleggen waarom dit gewenst zou zijn (meerdere voorbeelden enz..)? (En niet alleen omdat het handig is/lijkt). Anders wordt het net een welles/nietus verhaaltje...

[ Voor 4% gewijzigd door Anoniem: 201130 op 17-05-2007 22:43 ]


Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
flowerp schreef op donderdag 17 mei 2007 @ 22:36:
[...]


Uhhmmm...

flowerp in "[alg] Nut van overerving in static class..."

De MyOneAndOnlyResourceMessenger die ik daar noemde was toch aardig concreet...
Sorry, ik heb die reactie helemaal over het hoofd gezien. Maar dan blijf ik nog bij mijn punt dat voor dit soort dingen gewoon een singleton aangemaakt hoort te worden. Daarmee is het al opgelost. Want een ResourceMessenger lijkt me wel iets wat je wilt initialiseren en daarbij lijkt mij zo'n oplossing degelijk zo mooi, plus dat het "overervingsprobleem" direct is opgelost.
BalusC schreef op donderdag 17 mei 2007 @ 18:24:
Een static methode zou in feite gewoon een 'utility' methode moeten zijn (en omgekeerd). Oftewel ze doen alleen maar dezelfde acties op de gegeven invoerparameter(s). Dit soort methoden horen helemaal niet in een singleton. Maak de default constructeur van zo'n utilityklasse (een klasse met alleen maar static methoden) gewoon private.
Dit bedoel ik ook, maar utility methodes hebben volgens mij geen overerving nodig. Dus lijkt me het hier geen probleem.

Acties:
  • 0 Henk 'm!

  • flowerp
  • Registratie: September 2003
  • Laatst online: 20-05 21:31
Anoniem: 201130 schreef op donderdag 17 mei 2007 @ 22:43:
[...]
Er zijn 4 mensen die aangeven dat jouw voorbeeld lang niet zo concreet is en nauwelijks je punt bewijst en toch blijf je het beweren. Ook op het internet is weinig bijval te vinden voor jouw punt.
3 mensen, eentje had het verkeerd gelezen...:P
Kun jij nu eens goed uitleggen waarom dit gewenst zou zijn (meerdere voorbeelden enz..)?
Net zoals je met object inheritance het gedrag van de methods van een object kunt customizen, zou je kunnen beargumenteren dat je via 'class inheritance' het gedrag van de (static) methods op class niveau wilt kunnen customizen. Dat het anders kan is waar, maar ook op object niveau is inheritance niet altijd een vereiste.

Bij vele patterns kun je bv met zowel een is-a als een has-a relation uit de voeten. Moeten we daarom is-a maar afschaffen, omdat je er altijd om heen kunt werken?
(En niet alleen omdat het handig is/lijkt)
Dit vind ik niet echt een valide vraag. Zoals ik al eerder stelde; een groot percentage van alle dingen in een taal zijn 'handig' en niet 'nodig'. Enums? Zijn alleen maar handig, je kunt ze ook zelf maken. Var args? Ook alleen maar handig. Je werkt er zo om heen door b.v. een array mee te geven. Etc.

Het is ook een kwestie van consistentie, je kunt exact hetzelfde voorbeeld met objects maken, en dan werkt het wel op die manier.

Java:
1
2
3
4
5
6
7
8
9
10
11
12
class Base { static void func(){func1();} static void func1(){System.out.println("base:func1");} }
class Derived extends Base { static void func1(){System.out.println("Derived:func1");} }

class Base1 { void func(){func1();} void func1(){System.out.println("base:func1");} }
class Derived1 extends Base1 { void func1(){System.out.println("Derived:func1");} }

public class StaticInheritance {    
    public static void main(String[] args) {
        Derived.func(); // prints base:func1        
        new Derived1().func(); // prints Derived:func1
    }
}


Wat je nu ziet is dat in een static situatie WEL inheritance wordt toegepast, maar geen overide. Derived heeft geen definitie voor func(), maar toch kan ik deze erop aanroepen.

De objects in bovenstaande voorbeeld bevatten alleen maar methods en hebben geen enkele state.

De call chain bij de object variant is: inherited member van base -> overiden method in derived.
De call cain van de static variant is; inherited member van base -> original method in base.

Misschien moeten we de vraag eens op meerdere manieren omdraaien:

1) kun jij mij eens uitleggen waarom inheritance + method overide in de object situatie wenselijk is als je de method call via een derived doet (dus geen polymorphisme)? Graag meerdere voorbeelden geven.

2) Kun jij mij eens uitleggen waarom inheritance + method overide in de class situatie niet wenselijk is? Waarom is het evil? Welke problemen treden er op? Graag meerdere voorbeelden geven.

3) Kun jij mij eens uitleggen waarom static inheritance wel bestaat in Java? (bedenk dat je het antwoord "omdat het handig is" niet mag geven) Ook hier weer graag meerdere voorbeelden.

[ Voor 4% gewijzigd door flowerp op 18-05-2007 01:12 ]

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
flowerp schreef op vrijdag 18 mei 2007 @ 01:04:
[...]


3 mensen, eentje had het verkeerd gelezen...:P
Ik had wel verkeerd gelezen, maar blijf wel bij mijn punt ;)
[...]
1) kun jij mij eens uitleggen waarom inheritance + method overide in de object situatie wenselijk is als je de method call via een derived doet (dus geen polymorphisme)? Graag meerdere voorbeelden geven.
Zelfs in het abstracte voorbeeld die je zelf geeft zie je toch wel in dat je in een object situatie graag delen van de implementatie zelf wilt overiden. Zie bijvoorbeeld de OutputStream klasses in het Java API. Hierbij is OutputStream een abstracte klasses die alleen de write(int b) methode niet implementeerd en de rest een standaard implementatie geeft die afhankelijk is van die write(int b). Zelfs al doe je de calls op de derived object wil je natuurlijk wel dat er inheritance + method overide is, want anders kun je bijvoorbeeld niet meer BufferedOutputStream.write(byte[] b) doen ;) En zo zijn er nog voldoende voorbeelden te noemen. Het lijkt me dat dit punt niet echt iets duidelijk maakt, want dit is natuurlijk de basis van object orientatie.
2) Kun jij mij eens uitleggen waarom inheritance + method overide in de class situatie niet wenselijk is? Waarom is het evil? Welke problemen treden er op? Graag meerdere voorbeelden geven.
Natuurlijk treden er geen problemen op en in theorie is het prima te implementeren. Waarom het niet gedaan is, is dat er heel eenvoudig omheen te werken is (wanneer je het nodig hebt, kun je meestal wel er een object van maken d.m.v. een singleton pattern), en dat het niet implementeren van de method overide een grote snelheidswinst heeft voor de 'utility methods' die is zelf ook regelmatig gebruik.
3) Kun jij mij eens uitleggen waarom static inheritance wel bestaat in Java? (bedenk dat je het antwoord "omdat het handig is" niet mag geven) Ook hier weer graag meerdere voorbeelden.
Weer voor die utility methods die je gebruikt in een bepaald type object. Als je de top klasses dan een statische methode geeft (eventueel protected), dan heb je deze methode in alle subklasses direct voor handen. Ik moet wel zeggen dat daar tegenwoordig een alternatief voor is, namelijk de static import, maar deze is pas beschikbaar sinds Java 5, plus dat je dan bij elke klasse die hem wil gebruiken die import moet hebben. Als je een utility methode hebt die je in heel veel subklasses tegenkomt (en dus waarschijnlijk behoorlijk specifiek voor die klasse is), kun je alsnog overwegen om deze gewoon in de top klasse te declareren.
Een voorbeeld?

Java:
1
2
3
4
5
6
7
8
9
10
11
public abstract class ASTNode {
  ...
  private static String newLine = System.getProperty("line.separator");

  protected static void addLine(StringBuilder sb, Object... os) {
    for(Object o : os) {
      sb.append(o);
    }
    sb.append(newLine);
  }
}


Even een beetje uitleg: een ASTNode is een basisklasse voor alle nodes in de Abstract Syntax Tree (AST) die is gebruik in mijn compiler. Een redelijk aantal nodes kunnen echter code genereren, en zij doen dit allemaal m.b.v. StringBuilders (zodat er gewoon Strings gereturned kunnen worden). In plaats van nu allemaal de hele tijd dit te moeten doen:

Java:
1
sb.append(prefix).append(var.getName()).append(" = ").append(expr.getJavaCode()).append(newLine);


kan ik nu dit doen:

Java:
1
addLine(sb, prefix, var.getName(), expr.getJavaCode());


Dit is volgens mij veel duidelijk en handiger (of mocht ik dat niet zeggen ;)). Een andere oplossing is natuurlijk mijn eigen soort StringBuilder schrijven, maar StringBuilder is een final klasse (voor snelheids redenen) en kan dus niet meer uitgebreid worden. En een eigen StringBuilder maken is lastig is wel erg veel code in verhoudig tot deze oplossing.

Het mooie van de huidige implementatie van static methodes in de JVM is dat het heel makkelijk te inlinen is, want er kunnen nooit herimplementatie zijn. Daarom verlies ik met deze hulpfunctie nauwelijks snelheid. Niet dat snelheid het probleem in dit geval was, maar toch...

Hierbij heb ik toch wel duidelijk gemaakt dat het overerven van static methodes wel nodig is, maar dat het niet implementeren van overide toch echt wel voordelen biedt.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

flowerp schreef op donderdag 17 mei 2007 @ 11:29:
Ik weet het niet hoor. Dit is toch wel wat fundamenteler dan zo'n speciale operator. Uiteindelijk kun je alles wel met een minimale functionaliteit implementeren of omheen werken. Jij weet natuurlijk als geen ander dat alle taal constructies in C++ feitelijk overbodig zijn t.o.v. bijvoorbeeld C. Classes kun je gewoon zelf maken door structs en functie pointers te gebruiker, inheritence door een eigen vtable te implementeren, etc.
Het verschil tussen het probleem wat jij schetste en OO in C is dat OO een bepaald paradigma is dat niet echt in C bestaat, maar op low-level wel te simuleren is met relatief veel werk. Virtual static is geen paradigma maar een heel erg kleine feature. Sowieso heeft abstract static implicaties die pas @ runtime ondekt kunnen worden*1, maar het probleem wat jij schetst zou je imho ook misdesign kunnen noemen (wat Exiss dus ook al aangaf). Er bestaan gewoon hele mooie OO oplossingen voor dit probleem, bijv. doormiddel van een interface die je meegeeft aan de static functie in de base. Dan is het ook nog eens generieker dan met virtual static methods.

*1
Java:
1
2
3
4
5
class Test
{
    abstract static void foo();
    static void bar() { foo(); }
}


Test.bar() kan alleen aangeroepen worden door DerivedTest.bar() te doen, want anders is er geen implementatie voor foo().

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.


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11:01

.oisyn

Moderator Devschuur®

Demotivational Speaker

flowerp schreef op vrijdag 18 mei 2007 @ 01:04:
1) kun jij mij eens uitleggen waarom inheritance + method overide in de object situatie wenselijk is als je de method call via een derived doet (dus geen polymorphisme)? Graag meerdere voorbeelden geven.
Ik snap niet precies wat je hier bedoelt. Ook al doe je de call direct op een derived, nog steeds heb je polymorphisme (die derived kan immers ook zelf weer een derived hebben)
2) Kun jij mij eens uitleggen waarom inheritance + method overide in de class situatie niet wenselijk is? Waarom is het evil? Welke problemen treden er op? Graag meerdere voorbeelden geven.
Ik heb al meerdere problemen geschetst.
3) Kun jij mij eens uitleggen waarom static inheritance wel bestaat in Java? (bedenk dat je het antwoord "omdat het handig is" niet mag geven) Ook hier weer graag meerdere voorbeelden.
Waarschijnlijk omdat dat is overgenomen uit andere talen. Maar veel bedrijven hebben tussen de coding guidelines ook staan dat je een static methode gewoon juist moet aanroepen - op de class waarin hij gedefinieerd is. Base.func() dus, en niet Derived.func() als Derived 'm niet override, en ook niet op een instance. Ik kan het hier wel mee eens zijn, het maakt het lezen van code alleen maar lastiger als je alle varianten toelaat.

[ Voor 38% gewijzigd door .oisyn op 18-05-2007 13:12 ]

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.


Acties:
  • 0 Henk 'm!

  • Jrz
  • Registratie: Mei 2000
  • Laatst online: 06:29

Jrz

––––––––––––

Marcj schreef op vrijdag 18 mei 2007 @ 09:41:
[...]
Dit is volgens mij veel duidelijk en handiger (of mocht ik dat niet zeggen ;)). Een andere oplossing is natuurlijk mijn eigen soort StringBuilder schrijven, maar StringBuilder is een final klasse (voor snelheids redenen) en kan dus niet meer uitgebreid worden. En een eigen StringBuilder maken is lastig is wel erg veel code in verhoudig tot deze oplossing.

Het mooie van de huidige implementatie van static methodes in de JVM is dat het heel makkelijk te inlinen is, want er kunnen nooit herimplementatie zijn. Daarom verlies ik met deze hulpfunctie nauwelijks snelheid. Niet dat snelheid het probleem in dit geval was, maar toch...

Hierbij heb ik toch wel duidelijk gemaakt dat het overerven van static methodes wel nodig is, maar dat het niet implementeren van overide toch echt wel voordelen biedt.
lol.. wel nodig? je kan static in die method gewoon weghalen hoor.
Zal ook 0 snelheidswinst opleveren. Die ene push van this merk je echt niet. StringBuilder / buffer zijn zowiezo langzaam omdat ze bij elke append() het resultaat maken, terwijl je dat vaak pas wil als je toString() aanroept. Anders maak je hem lekker final, dan kan de JVM ook leuke dingen doen. Net als je parameters final maken.. dan zou er in principe geen kopie van de reference gemaakt te hoeven worden (=4 copies in jouw code). Of dit gebeurt is een tweede maar goed. Denk het niet eigenlijk, omdat die informatie afaik niet wordt opgeslagen in de class file.


ugh.. kan ik dit topic uit mn search my topics lijstje halen? irriteer me altijd aan dit soort geneuzel.
Net zoeits als mensen die variabelen on the fly willen maken, ipv maps te gebruiken haha

[ Voor 48% gewijzigd door Jrz op 18-05-2007 13:18 ]

Ennnnnnnnnn laat losssssssss.... https://github.com/jrz/container-shell (instant container met chroot op current directory)


Acties:
  • 0 Henk 'm!

Anoniem: 49627

Jrz schreef op vrijdag 18 mei 2007 @ 13:16:
ugh.. kan ik dit topic uit mn search my topics lijstje halen? irriteer me altijd aan dit soort geneuzel.
Net zoeits als mensen die variabelen on the fly willen maken, ipv maps te gebruiken haha
Ik erger me aan mensen die 'irriteren' als wederkerend werkwoord gebruiken. Het irriteert me. Maar meestal reageer ik dan gewoon niet :+

Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
Jrz schreef op vrijdag 18 mei 2007 @ 13:16:
[...]

lol.. wel nodig? je kan static in die method gewoon weghalen hoor.
Zal ook 0 snelheidswinst opleveren. Die ene push van this merk je echt niet. StringBuilder / buffer zijn zowiezo langzaam omdat ze bij elke append() het resultaat maken, terwijl je dat vaak pas wil als je toString() aanroept. Anders maak je hem lekker final, dan kan de JVM ook leuke dingen doen. Net als je parameters final maken.. dan zou er in principe geen kopie van de reference gemaakt te hoeven worden (=4 copies in jouw code). Of dit gebeurt is een tweede maar goed. Denk het niet eigenlijk, omdat die informatie afaik niet wordt opgeslagen in de class file.
Nodig is misschien niet het goed woord, misschien handig? ;) Daarnaast:

1) De static is (voor mij in ieder geval) om aan te geven dat deze functie het object zelf niet gebruikt, maar dat het een hulpfunctie is. Dit is misschien niet het beste voorbeeld, maar dit soort functies gebruik ik wel vaker.
2) De StringBuilder is echt wel snel en bij elke append() wordt niet het resultaat aangemaakt. Intern heeft hij gewoon een char[] die eventueel groter gemaakt wordt wanneer deze het resultaat niet meer kan vasthouden. Door de standaard grootte op 1024 characters te zetten zal dit niet zo vaak gebeuren. Hoe wil je dit anders doen? Als je me niet gelooft, kijk maar eens in de sourcecode van de java library (die zit gewoon bij de JDK). Pas bij de toString() functie wordt van die char[] een String gebouwd.
3) In dit geval zal het misschien niet zoveel snelheid schelen, maar ik probeer hier uit te leggen waarom de makers van Java ervoor gekozen hebben om static methodes niet te kunnen overiden :)
4) Deze functie was nooit gebouwd om heel snel te zijn ofzo (hij is snel zat), anders had ik geen variabele parameter gebruikt (hiervoor wordt namelijk elke keer een array aangemaakt, dat je daar dan weer niet over valt ;))
ugh.. kan ik dit topic uit mn search my topics lijstje halen? irriteer me altijd aan dit soort geneuzel.
Net zoeits als mensen die variabelen on the fly willen maken, ipv maps te gebruiken haha
Niet reageren kan ook helpen O-)

Misschien kan ik nog een anders voorbeeld geven waar static overerving wel handig is: bij constante waardes. Deze worden veel gebruikt in de Java library. Kijk bijvoorbeeld eens naar java.awt.Frame.NORMAL. Deze constante kun je nu ook heel makkelijk is alle subklassen van een Frame gebruiken zonder deze te moeten importen of direct naar te moeten laten verwijzen.
Dit is gewoon een feature die alleen in de compiler zit (die kan namelijk eenvoudig achterhalen waar je naar verwijst) en de JVM heeft er geen last van. Het overiden van static methodes ligt echter wat lastiger en heeft men dus achterwege gelaten voor snelheid (denk ik dan :))

Drie keer doorlezen, heb ik nu nog iets getyped wat verkeerd opgevat kan worden? :X

Acties:
  • 0 Henk 'm!

  • Jrz
  • Registratie: Mei 2000
  • Laatst online: 06:29

Jrz

––––––––––––

Marcj schreef op vrijdag 18 mei 2007 @ 14:10:
[...]
2) De StringBuilder is echt wel snel en bij elke append() wordt niet het resultaat aangemaakt. Intern heeft hij gewoon een char[] die eventueel groter gemaakt wordt wanneer deze het resultaat niet meer kan vasthouden. Door de standaard grootte op 1024 characters te zetten zal dit niet zo vaak gebeuren. Hoe wil je dit anders doen? Als je me niet gelooft, kijk maar eens in de sourcecode van de java library (die zit gewoon bij de JDK). Pas bij de toString() functie wordt van die char[] een String gebouwd.
Precies. Als StringBuffer nou gewoon een array / linked list gebruikt voor het bewaren van de Strings die worden toegevoegd, dan kan je het arraycopyen / alloceren / resizen uitstellen en optimaal maken door de lengtes van de strings op te tellen, array maken, en daar de strings in te copyen.
3) In dit geval zal het misschien niet zoveel snelheid schelen, maar ik probeer hier uit te leggen waarom de makers van Java ervoor gekozen hebben om static methodes niet te kunnen overiden :)
Om de reden die oisyn (leeft #nlcoders nog?;)) gaf. Je krijgt onduidelijkheid over wat nou wordt aangeroepen wanneer. +
4) Deze functie was nooit gebouwd om heel snel te zijn ofzo (hij is snel zat), anders had ik geen variabele parameter gebruikt (hiervoor wordt namelijk elke keer een array aangemaakt, dat je daar dan weer niet over valt ;))
Niet opgevallen.
Niet reageren kan ook helpen O-)
Doe ik vaak genoeg hahaha. Dan heb ik weer een of andere lap tekst getikt, en dan denk ik nah.. toch maar niet posten lol
Misschien kan ik nog een anders voorbeeld geven waar static overerving wel handig is: bij constante waardes. Deze worden veel gebruikt in de Java library. Kijk bijvoorbeeld eens naar java.awt.Frame.NORMAL. Deze constante kun je nu ook heel makkelijk is alle subklassen van een Frame gebruiken zonder deze te moeten importen of direct naar te moeten laten verwijzen.
Dit is gewoon een feature die alleen in de compiler zit (die kan namelijk eenvoudig achterhalen waar je naar verwijst) en de JVM heeft er geen last van. Het overiden van static methodes ligt echter wat lastiger en heeft men dus achterwege gelaten voor snelheid (denk ik dan :))
Ik ben ook helemaal niet tegen static methods / constanten / zoals jij ze gebruikt hoor.

Maar ik zag als reden snelheid staan :|

Ennnnnnnnnn laat losssssssss.... https://github.com/jrz/container-shell (instant container met chroot op current directory)


Acties:
  • 0 Henk 'm!

  • Marcj
  • Registratie: November 2000
  • Laatst online: 14:24
Jrz schreef op vrijdag 18 mei 2007 @ 16:00:
[...]
Precies. Als StringBuffer nou gewoon een array / linked list gebruikt voor het bewaren van de Strings die worden toegevoegd, dan kan je het arraycopyen / alloceren / resizen uitstellen en optimaal maken door de lengtes van de strings op te tellen, array maken, en daar de strings in te copyen.
[..]
Dit is ook een mogelijke implementatie, maar dit kan ook zeker problemen opleveren qua geheugengebruik. Weet je bijvoorbeeld wat de String.substring() methode voor String oplevert? Eentje die een referentie heeft naar het origineel. Hierdoor kan het origineel niet uit het geheugen gegooid worden en zou dit potentieel behoorlijk wat extra geheugen kosten.
Daarnaast moet je wel onthouden dat je voor elk object die je onthoud een extra 20 extra bytes bewaart (16 bytes extra voor het String object + 4 bytes voor de referentie), dus wat op de lange duur efficienter is moet ik nog zien...

Maar goed, dit gaat weer helemaal offtopic, want we hadden het over de abstract static methodes :) En daarover zijn we het dus wel redelijk eens, alleen flowerp nog niet helemaal...
Pagina: 1