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

[disc-taal] welke features erin en welke eruit.

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

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik ben nu al een tijdje aan het experimenteren met een taal extensie van java: Nice. Deze heeft oa geparametriseerde types, anonieme functies, multi methods (dus multi dispatch) inner functies, mooie nullchecks, en nog veel meer andere leuke dingen.

Ik zie nu ineens wat voor dingen ik eigelijk bij Java allemaal mis. Wat ik me eigelijk afvraag is wat voor features jij jullie eigelijk in een taal zouden willen hebben, of juist er niet in gehad zou willen hebben (bv goto statements).

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik denk dat Nice wel aardig in de buurt komt al. Misschien iets meer support voor distributed programming, maar in Java is elke class al een monitor toch? Wat features van Orca zouden wel handig zijn. Ik programmeer nu liever in Orca dan in Java voor dit soort apps, maar orca met java syntax zou ideaal zijn.

Verder denk ik dat C++ het al heel goed doet. Misschien zou het iets stricter kunnen, en wat extra in gebouwde compile time features, zoals Loki en Boost nu hebben. Aan de andere kant is voor het C++ standpunt van "als je het zelf kan schrijven, hoeft het niet in de taal" ook wel wat te zeggen.

Java heeft geen multiple inheritance toch? (alleen via interfaces) En Nice? Dat is toch ook wel een wenselijke feature. Zodat je makkelijk met traits kan programmeren.

Ik denk dat er op het gebied van error checking ook nog wel een en ander veranderd kan worden. Exceptions zijn leuk, en werken iha wel oke; maar misschien iets van automatische pre- en post-conditie checks? Design by contract dus. Ik weet niet tot hoever dit mogelijk is, bepaalde dingen kun je nl theoretisch niet na gaan . (niet turing computable, zoals program termination)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Zoijar schreef op 25 augustus 2002 @ 13:29:
Ik denk dat Nice wel aardig in de buurt komt al. Misschien iets meer support voor distributed programming, maar in Java is elke class al een monitor toch?
Alleen als je de methodes synchronized maakt.
Wat features van Orca zouden wel handig zijn. Ik programmeer nu liever in Orca dan in Java voor dit soort apps, maar orca met java syntax zou ideaal zijn.
Ik heb eerlijk gezegd nog maar weinig gedaan met distributed programming en eigelijk hebben de huidige mogelijkheden in java altijd nog goed voldaan (RMI/Corba) Misschien dat het bij grotere projecten handiger is om wat meer ondersteuning te krijgen van de taal.
Verder denk ik dat C++ het al heel goed doet. Misschien zou het iets stricter kunnen, en wat extra in gebouwde compile time features, zoals Loki en Boost nu hebben. Aan de andere kant is voor het C++ standpunt van "als je het zelf kan schrijven, hoeft het niet in de taal" ook wel wat te zeggen.
Sommige dingen zijn langdradig en vervelend om te schrijven en het is handiger om vanuit de taal ondersteuning te krijgen. Anders zou je net zo goed in asm kunnen proggen. Ik zie dus graag wel handige features in een taal, hierdoor werk je gewoon een stuk sneller en maak je minder fouten. Tevens is je code vaak een stuk leesbaarder.
Java heeft geen multiple inheritance toch? (alleen via interfaces) En Nice?
Ze hebben beiden geen multiple inheritance met classes alleen inderdaad met interfaces. Ik ben zelf eigelijk hier wel van gecharmeerd omdat je ook wel meerdere classes met elkaar kan combineren. Dit kan verder alleen als je je systeem goed hebt opgezet met interfaces. Ik denk dat dit voor een c++ programmeur een beetje een vreemde gewaarwording is. Maar je kunt het beste ontwerpen vanuit interfaces zodat je iedere class erachter kan plakken. Hierdoor kan je gewoon multiple inheritance krijgen zonder alle akelige problemen die daar bij horen.
Ik denk dat er op het gebied van error checking ook nog wel een en ander veranderd kan worden. Exceptions zijn leuk, en werken iha wel oke; maar misschien iets van automatische pre- en post-conditie checks? Design by contract dus.
Vanaf Nice 1.0 :)
Ik weet niet tot hoever dit mogelijk is, bepaalde dingen kun je nl theoretisch niet na gaan . (niet turing computable, zoals program termination)
Ik denk dat dit een hele lastige zaak gaat worden.

Wat ik op dit moment doe om mijn code te checken is gebruik maken van Unit testen. Hiermee kan je objecten door laten meten. Dit is echt superhandig omdat je die testen gewoon na het compileren kan laten uitvoeren en je gewoon meer vertrouwen krijgt in je software.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
Even een rijtje punten, waar echter nog zeker een selectie procedure op los moet worden gelaten ;) .

1) Zoveel mogelijk taal constructies expressies zijn en in het algemeen het aantal non-terminals in de taal beperkt is. Ik denk tov Java dan aan if-then-else statements en try-catch statements.

Assignments zou ik echter juist weer niet als expressies willen zien en in ruil daarvoor zou ik expressie-blocken wileln zien. Een expressie block is het volgende:

code:
1
"{" Stm Expr "}" -> Expr


In woorden: een aantal statements, gevolgd door een expressie is een expressie. Een assignment als expressie moet dan vervangen worden door deze constructie:

code:
1
{ x := 5; x}


De 'blocks' onder if-then-else statements en try-catch statements mogen ook dergelijke expressie blocken zijn, waardoor je het volgende zou kunnen doen:

code:
1
2
3
4
5
6
7
int x = try{
             doSomethingDangerous()
         } catch( Exception exc) {
             13
         }

int x = if ( y < 3) {  y * 4  } else {  y * 3 }


Bodies van functies zouden bijvoorbeeld ook expressie-blocken zijn:

code:
1
2
3
4
5
public int doSomething() {
    int result;
    ......
    result
}


2) Er geen onderscheid is tussen primitieven en objecten. Het onderscheid tussen primitieven en objecten is een optimalisatie detail waar je de programmeur niet lastig mee hoeft te vallen. Compiler technologie en de snelheid van computers is zo ver gevorderd dat een compiler lekker zelf kan gaan uitzoeken wanneer er primitieven gebruikt kunnen worden. Liefst moet dit gedrag ook nog doorgetrokken worden naar alle objecten en niet alleen naar de zaken die nu al primitief zijn. Overigens zie ik dus liever een andere oplossing dan in C#, waar er een scheiding is tussen klassen en value-types en primitieve waarden gebruikt kunnen worden als objecten via auto-boxing. Dit zijn (logische) lapmiddelen en geen echte oplossing van het probleem.

3) Er zou een aparte taal-constructie moeten zijn om aan te geven dat een bepaalde variabele de waarde null mag hebben of niet. Ik doel hiermee uiteraard op het ? van Nice.

4) Weinig of geen syntaxtische varianten met dezelfde betekenis. Arrays in Java kan je bijvoorbeeld wel op heel erg veel manieren noteren. Waardeloos. 1 methode is veel duidelijker.

5) Overflow checks en checked conversions zoals in C#

6) Array index checks

7) Syntaxtische suiker voor lijsten, tuples etc. Eventueel zou het ook heel fraai zijn als je zelf naar behoefte syntaxtische suiker kan toevoegen (wat veel verder gaat dan alleen operator overloading), maar dit gaat wellicht wat ver voor een mainstream taal.

8) Functioneel achtige capaciteiten: map, folds, functies meegeven, liefst zelfs volledige hogere orde functies. Python is een aardig voorbeeld van hoe leuk een niet perfecte oplossing al kan zijn.

9) Laten we nu eindelijk eens dapper genoeg zijn om assignments als := te introduceren in een mainstream taal. Inhoudelijke vergelijking (.equals) kan = worden en pointer vergelijk kan == worden.

10) Betere pattern-matching mogelijkheden: methode declaraties zouden ook patronen moeten kunnen bevatten, waardoor je methoden kan implementeren in varianten voor verschillende mogelijke patronen. Op dit moment bieden de meeste talen alleen een soort pattern-matching op het type van de eerste of verdere parameters. Je kan methoden overloaden, waardoor je een methode op verschillende manieren kan implementeren voor verschillende typen. Waarom niet verder gaan en krachtige pattern-matching op de inhoud van objecten invoeren? Dit heeft ook een beetje te maken met multi-methods, maar gaat eigenlijk nog verder.

11) Geparameterizeerde typen, maar spreekt voor zich ;) .

12) Fuck de optionele taal-constructies: gewoon altijd de toegang van een methode/klasse/veld aangeven. Daarom moet er ook een aparte modifier komen voor package access.

13) Super constructor call buiten de constructor zoals in C#. In de constructor zelf zorgen ze al snel voor verwarring.

14) Waarom moet je een constructor de naam van klasse geven :? Noem hem gewoon 'constructor'. Veel duidelijker.

15) Attributen zoals in C#

16) Geen assigment aan parameters: parameters zijn standaard final

17) Serie aanroepen op een object: in de Java library zie je dat steeds meer methoden 'this' gaan opleveren zodat er gelijk weer een methode kan worden aangeroepen op het resultaat. Dit werkt sterk vervuilend omdat je de documentatie moet raadplegen om te zien of er ook daadwerkelijk 'this' of een nieuw object wordt opgeleverd. Daarom moet er een taal constructie komen die het mogelijk maakt om meerdere methoden achter elkaar aan te roepen op een object. Voorbeeldje:

18) Entry point van een applicatie sterk verbeteren: static main eruit en vervangen door een interface Application of iets dergelijks die je moet implementeren.

19) ";" liever als scheidings teken tussen statements dan als afsluiting van een statement ...

20) Een taal waarin (eventueel met behulp van semantische analyse) de betekenis van elke constructie kan worden bepaald zonder daarbij externe bestanden of libraries te moeten raadplegen. Dit is uitermate belangrijk voor meta-tools rond een taal zoals tools die helpen bij refactoring. In Java is er bijvoorbeeld het probleem dat de "." gebruikt wordt voor field-access, maar ook als scheidings teken tussen packages.

Voorbeeld:
code:
1
org.mbravenboer.Klasse.somefield.someotherfield

Wie weet is "org" wel een klasse... Wie weet is "mbravenboer" wel een klasse ... Wie weet is somefield ook nog wel een klasse?

Dit zijn echter hele vervelende zaken die erg veel vragen van meta-tools. Hier is duidelijk niet over nagedacht, anders was er vast een andere constructie gekozen. Er wordt vaak gezegd dat C niet context-vrij te parsen is (wat klopt), maar ik zou dit eigenlijk willen doortrekken naar Java. Vanwege de situatie hierboven is er namelijk een "ambigious name" opgenomen in de grammatica van Java. Lijkt mij niet echt de oplossing.

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


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Alarmnummer schreef op 25 augustus 2002 @ 14:55:

Alleen als je de methodes synchronized maakt.
Ok, zoiets dacht ik al.
Ik heb eerlijk gezegd nog maar weinig gedaan met distributed programming en eigelijk hebben de huidige mogelijkheden in java altijd nog goed voldaan (RMI/Corba) Misschien dat het bij grotere projecten handiger is om wat meer ondersteuning te krijgen van de taal.
Het mooie bij orca is het runtime systeem. Zo wordt er "dynamic object placement" ondersteund. Objecten kunnen als "shared" geclassificeerd worden, en dan zonder enig verder toedoen kan je het object aanspreken vanaf elke node. Verder wordt er compile-time (statische voorspelling) en run-time (dynamische statistieken) een read/write ratio bijgehouden. Als deze hoog is, dan wordt het object automatisch replicated over alle nodes (locale read, broadcast write); als de ratio laag is wordt het object op een enkele node geplaatst en gebruiken de andere nodes voor zowel read als write RMI.
Sommige dingen zijn langdradig en vervelend om te schrijven en het is handiger om vanuit de taal ondersteuning te krijgen. Anders zou je net zo goed in asm kunnen proggen. Ik zie dus graag wel handige features in een taal, hierdoor werk je gewoon een stuk sneller en maak je minder fouten. Tevens is je code vaak een stuk leesbaarder.
Ja daar ben ik het mee eens. Ik zie ook graag typelists ed van Loki in de volgende C++ standaard.
Ze hebben beiden geen multiple inheritance met classes alleen inderdaad met interfaces. Ik ben zelf eigelijk hier wel van gecharmeerd omdat je ook wel meerdere classes met elkaar kan combineren. Dit kan verder alleen als je je systeem goed hebt opgezet met interfaces.
Het is lastig om een trait interface te maken. Helemaal als het je bv om typedefs gaat, zoals in de standaard library veelvuldig gebruik van wordt gemaakt.
Aan de andere kant is de Java manier "veiliger" en netter. Toch heb ik hier liever iets meer vrijheid.
Vanaf Nice 1.0 :)

Ik denk dat dit een hele lastige zaak gaat worden.

Wat ik op dit moment doe om mijn code te checken is gebruik maken van Unit testen. Hiermee kan je objecten door laten meten. Dit is echt superhandig omdat je die testen gewoon na het compileren kan laten uitvoeren en je gewoon meer vertrouwen krijgt in je software.
Ja het is lastig om elk control path te testen. Helemaal met vage fouten, zoals out-of-memory exceptions of overflows. Ik vind het van Java wel goed dat je elke mogelijke exception af moet vangen. Het is heel verleidelijk in C++ om die std::bad_alloc maar gewoon te negeren als je bv een klein object aanmaakt, een geometrische vector oid. En dan ook nog zelf je garbage correct moeten collecten. Veel van dit soort routines worden nooit grondig getest.

  • tomato
  • Registratie: November 1999
  • Niet online
mbravenboer schreef op 25 augustus 2002 @ 15:01:
17) Serie aanroepen op een object: in de Java library zie je dat steeds meer methoden 'this' gaan opleveren zodat er gelijk weer een methode kan worden aangeroepen op het resultaat. Dit werkt sterk vervuilend omdat je de documentatie moet raadplegen om te zien of er ook daadwerkelijk 'this' of een nieuw object wordt opgeleverd. Daarom moet er een taal constructie komen die het mogelijk maakt om meerdere methoden achter elkaar aan te roepen op een object. Voorbeeldje:
code:
1
ageNextMonth = myFamily.getFather().getAge().add(new Month());

Je doelde op zoiets neem ik aan ;)

[edit]
Nog een keertje lezen, waarschijnlijk toch meer iets als dit (maar dan in syntax waar beter over nagedacht is):
code:
1
myFamily. setFather(new Person()), setMother(new Person()), setAddress(new Address());

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

tomato schreef op 25 augustus 2002 @ 15:17:
[...]

code:
1
ageNextMonth = myFamily.getFather().getAge().add(new Month());

Je doelde op zoiets neem ik aan ;)


nee ik denk meer zoiets:
code:
1
2
Vector3D v = new Vector3D ();
with v do { add (a), add (b), scale (5), cross (c) }


ofzo :)
al die methodes werken op v. In jouw voorbeeld werken ze gewoon op het resultaat van de vorige methode

.edit: idd, wat je zei in je edit ;)

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


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
tomato en .oisyn
Inderdaad, dat bedoel ik :) .

Eigenlijk kan je het zien als een normale methode aanroep, waarbij de 'current expression' hetzelfde blijft. Op Javahova hebben we het er een keer over gehad en Arien had toen een fraaie syntax bedacht. Helaas kan ik het topic niet meer vinden ivm de lekkere search daar .... De "." moet vervangen worden door een teken wat aangeeft dat je een methode aanroep doet zonder de 'current expression' te willen veranderen.

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik ben trouwens zelf een scripttaal aan het maken met ingebouwde statemachines.

In je klasse definieer je dan een state variabele (soort van enumeration), en je kunt methoden van die klasse dan koppelen aan die variabele, en voor elke state een aparte implementatie schrijven

Dit is enorm handig voor game logic (waar het ook voor bedoeld is :)), omdat je dan niet met wazige en slecht leesbare switch constructies hoeft te werken

voorbeeldje:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Ememy
{
    statevar { angry, affraid, normal, dead } mood;

    void onSeePlayer<mood: angry, normal> (Player p)
    {
        huntAndKill (p);
    }

    void onSeePlayer<mood: affraid> (Player p)
    {
        runAwayFrom (p);
    }

    void onSeePlayer<mood: dead> (Player p)
    {
        playDeadSomeMore ();  // ;)
    }
}


Welke methode wordt aangeroepen is nu afhankelijk van de waarde van mood
Verder hoeft niet voor elke state een implementatie geschreven te worden: als er voor een bepaalde state geen implementatie is gebeurd er gewoon niets (behalve als de methode een return type heeft, dan moeten ze wel geimplementeerd worden, maar daarvoor kun je een default implementatie gebruiken), en een default implementatie maak je met * (wat eigenlijk 'alle nog niet geimplementeerde states' betekent)

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


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
.oisyn: In je klasse definieer je dan een state variabele (soort van enumeration), en je kunt methoden van die klasse dan koppelen aan die variabele, en voor elke state een aparte implementatie schrijven
Ah, dat ziet er wel leuk uit ja :) . Het heeft veel te maken met het pattern-matching punt in mijn post (behalve dat je hier dus ook al niet meer de mood hoeft mee te geven).

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


  • tomato
  • Registratie: November 1999
  • Niet online
mbravenboer schreef op 25 augustus 2002 @ 15:37:
Op Javahova hebben we het er een keer over gehad en Arien had toen een fraaie syntax bedacht. Helaas kan ik het topic niet meer vinden ivm de lekkere search daar ....
code:
1
new StringBuffer() => append(..) => append( ... )

Gevonden in .Net, Parrot, C# boek, Free Software in Peru, etc
(op pagina 2, rond 9-5-2002 @21:28 begin je erover)

Verwijderd

Ik wil graag in elke taal een "foreach variabele in array/collection {}" willen hebben dat zou meteen een boel checks en iterators schelen
9) Laten we nu eindelijk eens dapper genoeg zijn om assignments als := te introduceren in een mainstream taal. Inhoudelijke vergelijking (.equals) kan = worden en pointer vergelijk kan == worden.
Doe er dan meteen een swap assignment bij iets als :=:
En als je op inhoud kunt vergelijken dan moet je ook op inhoud kunnen assignen dus een deepcopy assignment.
10) Betere pattern-matching mogelijkheden: methode declaraties zouden ook patronen moeten kunnen bevatten, waardoor je methoden kan implementeren in varianten voor verschillende mogelijke patronen. Op dit moment bieden de meeste talen alleen een soort pattern-matching op het type van de eerste of verdere parameters. Je kan methoden overloaden, waardoor je een methode op verschillende manieren kan implementeren voor verschillende typen. Waarom niet verder gaan en krachtige pattern-matching op de inhoud van objecten invoeren? Dit heeft ook een beetje te maken met multi-methods, maar gaat eigenlijk nog verder.
Misschien te combineren met precondities: functies overloaden en dan maar matchen op de precondities.
19) ";" liever als scheidings teken tussen statements dan als afsluiting van een statement ...
Oei dat zal ontwennen worden ;) (het heeft me hele tijd gekost om aan die 'overbodige' ";" te wennen en nu kan ik niet meer zonder :X )

Verder vindt ik dat alle constructies die je vaak gebruikt op een simpele korte en eenduidige manier moeten kunnen opschrijven.

Multimethods is een mooier alternatief voor het visitorpattern, waar blijven de alternatieven voor de andere design patterns? >:)

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op 25 augustus 2002 @ 15:38:
Ik ben trouwens zelf een scripttaal aan het maken met ingebouwde statemachines.
Dat kan je ook voor elkaar krijgen met het "State" design pattern. Alleen draai je het dan om, je zou zeggen dat je Enemy in een bepaalde "mood" is, en dan zijn gedrag veranderd. Je krijgt dus sub classes als "AngryEnemy" en "AfraidEnemy". Je hebt dan ook geen switch statements meer.

Maar het is wel erg handig om het in een scripting taal te hebben. Helemaal natuurlijk als je scripting ook AI primitieven ondersteund. Ziet er goed uit :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

[nohtml]
Zoijar schreef op 25 augustus 2002 @ 16:06:
[...]


Dat kan je ook voor elkaar krijgen met het "State" design pattern.
heb je daar meer info van (linkje ofzo)?
Alleen draai je het dan om, je zou zeggen dat je Enemy in een bepaalde "mood" is, en dan zijn gedrag veranderd. Je krijgt dus sub classes als "AngryEnemy" en "AfraidEnemy". Je hebt dan ook geen switch statements meer.
ok, maar hoe verander je dan van state? Stel ik heb een AngryEnemy, die bang moet worden omdat ik ineens een SuperBFG1043k tevoorschijn haal (ofzo :P). Moet er dan een nieuwe enemy (AfraidEnemy) geconstrueerd worden op basis van de oude AngryEnemy, zodat de AngryEnemy weggegooid kan worden?

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.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Hmm dit begint behoorlijk off-topic te raken :)

offtopic:
State

Je kan het met "flyweight" combineren, dan hoef je geen nieuwe enemy te maken, maar haal je hem uit een "state pool". Als je het dan zo schrijft dat je states kunnen werken met een doorgegeven "echte enemy", dus iets dat data heeft (dit is dan min of meer weer visitor) lijkt het me wel goed werken.

Dus zo op het eerste gezicht zou ik denken aan een combinatie van deze 3 patterns, State, Flyweight en Visitor. Misschien een goeie basis voor de implementatie van je scripting. Ff googlen ;)

Ik las het artikel net zelf even, en die "echte enemy" waar ik het over had is daar de Context. Ik zou het iets anders doen, dat je iets meer vrijheid hebt maar in principe werkt het goed.
Ook die ref naar het Null-Pattern is precies wat jij beschreef, dat als er geen expliciete definite is voor een bepaalde actie onder een bepaalde mood, dat er dan gewoon niks gebeurd.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 00:04

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op 25 augustus 2002 @ 16:56:
Hmm dit begint behoorlijk off-topic te raken :)
ach dat is met dit soort draadjes vrijwel altijd, en meestal komen ze uiteindelijk wel weer op het goede spoor terecht ;)
offtopic:
State

Je kan het met "flyweight" combineren, dan hoef je geen nieuwe enemy te maken, maar haal je hem uit een "state pool". Als je het dan zo schrijft dat je states kunnen werken met een doorgegeven "echte enemy", dus iets dat data heeft (dit is dan min of meer weer visitor) lijkt het me wel goed werken.

Dus zo op het eerste gezicht zou ik denken aan een combinatie van deze 3 patterns, State, Flyweight en Visitor. Misschien een goeie basis voor de implementatie van je scripting. Ff googlen ;)

Ik las het artikel net zelf even, en die "echte enemy" waar ik het over had is daar de Context. Ik zou het iets anders doen, dat je iets meer vrijheid hebt maar in principe werkt het goed.
Ook die ref naar het Null-Pattern is precies wat jij beschreef, dat als er geen expliciete definite is voor een bepaalde actie onder een bepaalde mood, dat er dan gewoon niks gebeurd.


ah zo
ja das idd ook een oplossing, maar imho een beetje omslachtig voor het doel wat ik wil bereiken. Bovendien zijn deze designpatterns niet nodig als het als feature in de taal 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.


  • Soultaker
  • Registratie: September 2000
  • Nu online
Een paar korte opmerkingen van mijn kant, hoewel ik me in veel van de voorgestelde features kan vinden:

In een taal waarin onderscheid bestaat, tussen objecten enerzijds en pointers/references anderzijds, is het definieren van afzonderlijke comparison operators (= en ==, zoals mbravenboer voorstelde) en assignment operators (zoals borganism voorstelde) zinloos. De discussie neigt onterecht naar het verbeteren van Java; het is helemaal niet gezegd dat onze hypothetische taal niet met objecten kan werken (zoals Java) maar uitsluitend met references. Blijkbaar zijn er verschillende operators die zowel in de context van een object (als waarde) en in de context van een reference naar dat object een andere betekenis hebben. Het lijkt mij dan geschikter om onderscheid te maken in objecten en references naar objecten, zodat niet voor elk onderscheid een aparte operator nodig is.

Multiple implementation inheritance vind ik een belangrijke feature van een object-georienteerde taal. Sterker nog: ik zou helemaal geen onderscheid willen zien tussen interfaces en implementaties. Zoals gezegd zijn in Java traits moeilijk te combineren met klassen die zelf al erven. Erg jammer en nergens voor nodig; nog niemand heeft mij uit kunnen leggen waarom implementation inheritance onoverkomelijke problemen oplevert vergeleken met interface inheritance. De aanwezigheid in de taal C++ bewijst dat het kan. Dat multiple implementation inheritance niet altijd noodzakelijk is, betekent niet dat het geen belangrijke feature kan zijn, die in ieder geval meer effect heeft op de eigenschappen van de taal dan bijvoorbeeld een deep copy operator (die ook wel met een constructor of een geschikt methode te benaderen is).

Ik ben absoluut tegen het gebruiken van ';' als statement seperator in plaats van statement terminator en ik dacht dat we er als programmeurs met z'n allen nu ook wel een keer over uit waren dat dat niet handig is. Volgens mijn zijn er nog ontzettend veel discussies (tussen Pascal en C gebruikers bijvoorbeeld) te vinden op internet, usenet en allerlei BBS'en. Indien gewenst wil ik nog wel een uitgebreide rant beginnen om mijn stelling kracht bij te zetten, maar dat gaat voor dit topic wat te ver. In de praktijk is in ieder geval te zien, dat ook Pascal programmeurs vaak alle statements beeindigen met een ';' in plaats van dit bij het laatste statement achterwege te laten (wat toegestaan is). In een taal als Perl is het bovendien al mogelijk om ook bij het definieren van lijsten de seperator (',') als terminator te gebruiken.

Daarbij wil ik nog de C++ feature van constante references en constante methoden noemen; dit is een sterke toevoeging aan het typesysteem.

Verwijderd

Ik zou eerst wel eens willen weten wat al die termen zijn die Alarmnummer op tafel gooit. :?

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Ik ben een beetje in twee strijd.

Ja, het is leuk om als (meer ervaren) programmeur meer gereedschap te krijgen om je taak nog beter, mooier en sneller te doen.

Aan de andere kant geeft het ook de mogelijkheid om een vreselijk onnavolgbaar en fout gevoelig stuk code te maken. Ik verkies leesbaarheid vaak over snelheid. Dit omdat mijn collega programmeurs het beter en sneller kunnen begrijpen. Ook als ikzelf na een tijdje weer naar mijn code kijk wil ik niet eerst 10 minuten staren voordat ik doorheb wat er in een simpele loop gebeurd.

C++ Templates zijn geweldig. Je hoeft maar 1 klasse List te maken en het werkt theoretish op alle types. Maar vaak wordt de code van de List zelf onnodig ingewikkeld en onderzichtig en veroorzaakt het op de raarste plaatsen bugs, terwijl je eigenlijk alleen een IntegerLijst nodig had.

Een C for loop is erg krachtig en je kan er erg mooie code mee maken, maar helaas kan je er ook erg vieze, zwakke en onbegrijpbare code mee maken.

Het blijft dan ook een kwestie van smaak en de juiste tools for the job kiezen. Maar het is niet altijd: hoe meer opties, des te beter.

Kijk ook naar wat er gebeurd met Garbage Collection. Waarom wordt programmeurs de vrijheid afgenomen zelf te bepalen wanneer ze klaar zijn met een object?

We adore chaos because we like to restore order - M.C. Escher


  • Soultaker
  • Registratie: September 2000
  • Nu online
Verwijderd schreef op 25 augustus 2002 @ 17:32:
Ik zou eerst wel eens willen weten wat al die termen zijn die Alarmnummer op tafel gooit. :?
geparametriseerde types
Types die geinstantieerd worden afhankelijk van andere types; veel gebruik in functionele programmeertalen en C++. Een voorbeeld:
code:
1
2
add :: A A -> A
add x y = x + y

Deze methode werkt voor alle typen waarvoor de + operator gedefinieerd is. In een 'normale' objectgeorienteerde zou dit ook zo kunnen:
code:
1
2
3
4
Numeral add(Numeral x, Numeral y)
{
   return x + y;
}

Maar het verschil is dat in het laatste voorbeeld de feitelijke typen van de parameters verloren gaat, terwijl in het eerste voorbeeld het resultaat van de functie van het type van de parameters is.

anonieme functies
Ik gok dat hiermee functies zonder identifier bedoeld worden; ook wel bekend als lambda-expressies. In functionele programmeertalen kom je ze vaak tegen:
code:
1
map (\x = x + 2) [1, 2, 3]

Hierbij is (\x = x + 2) dus een functie zonder feitelijk naam. Deze functie bestaat dus niet als globale functie of lokale functie (methode van een klasse).

multi methods
Dynamische selectie van methoden op basis van alle parameters (en niet alleen het object waarop de methode wordt aangeroepen). Zie voor details Alarmnummer's tutorial/FAQ-addition over het Visitor pattern.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Soultaker schreef op 25 augustus 2002 @ 17:29:
Multiple implementation inheritance vind ik een belangrijke feature van een object-georienteerde taal. Sterker nog: ik zou helemaal geen onderscheid willen zien tussen interfaces en implementaties. Zoals gezegd zijn in Java traits moeilijk te combineren met klassen die zelf al erven. Erg jammer en nergens voor nodig; nog niemand heeft mij uit kunnen leggen waarom implementation inheritance onoverkomelijke problemen oplevert vergeleken met interface inheritance. De aanwezigheid in de taal C++ bewijst dat het kan. Dat multiple implementation inheritance niet altijd noodzakelijk is, betekent niet dat het geen belangrijke feature kan zijn, die in ieder geval meer effect heeft op de eigenschappen van de taal dan bijvoorbeeld een deep copy operator (die ook wel met een constructor of een geschikt methode te benaderen is).
Ik heb nooit multiple inheritance is C++ gedaan, maar leg mij eens uit wat de onderstaande pseudo c++ code doet:

class A{
void SomeFunction();
void AmbiguentFunction();
}

class B{
void SomeOtherFunction();
void AmbiguentFunction();
}

class C = A, B{
}

C CTest = new C;
C->AmbiguentFunction();

Welke wordt er aangeroepen?

We adore chaos because we like to restore order - M.C. Escher


  • tomato
  • Registratie: November 1999
  • Niet online
LordLarry schreef op 25 augustus 2002 @ 17:52:
Ik heb nooit multiple inheritance is C++ gedaan, maar leg mij eens uit wat de onderstaande pseudo c++ code doet:
Ik heb nooit multiple inheritance gebruikt (nooit een taal waarin het kan, of heeft Python het?), maar volgens mij heb je dan een 'method clash'.
Je kunt dit denk ik oplossen door class C AmbiguentFunction(); te laten implementeren, anders krijg je waarschijnlijk een error van de resolver (of wellicht pas een runtime error wanneer je method wordt aangeroepen). Ik geloof niet dat de compiler er iets mee doet.

[edit] Klopte dus ook niet helemaal, zie de post van Soultaker hier onder :)

  • Soultaker
  • Registratie: September 2000
  • Nu online
Geen van beiden; je krijgt een compile-time error, die je kunt oplossen door expliciet te specificeren welke methode je wilt gebruiken:
code:
1
2
C->A::AmbiguentFunction();
C->B::AmbiguentFunction();


De methode opnieuw implementeren in klasse C is in de meeste gevallen niet de bedoeling en zelfs dan zul je misschien toch de implementatie van A of B willen aanroepen.

Python ondersteunt, als ik me niet vergis, inderdaad een beperkte vorm van multiple implementation inheritance.

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Dit is een veel groter probleem bij MI:

class A {int i;};
class B : public A {};
class C: public A{};
class D: public B, C {};

Maar daar is "virtual" inheritance voor (class X : virtual public Y) Dus nog steeds geen onoverkomelijk probleem.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
Soultaker: In een taal waarin onderscheid bestaat, tussen objecten enerzijds en pointers/references anderzijds, is het definieren van afzonderlijke comparison operators en assignment operators zinloos.
Ach, dan kunnen we heel lang gaan discussieren over er in een taal onderscheid moet zijn tussen objecten en pointers/references :+ . Kansloze discussie uiteraard.
Het lijkt mij dan geschikter om onderscheid te maken in objecten en references naar objecten, zodat niet voor elk onderscheid een aparte operator nodig is.
In die redenering zit inderdaad wel wat, maar ik vraag me af of het de moeite waard is om (vanuit Java/C# gezien) alleen om deze reden terug te gaan naar een taal constructie voor pointers naar objecten (eigenlijk een taal-constructie voor geen pointers naar objecten ;) ).
Multiple implementation inheritance vind ik een belangrijke feature van een object-georienteerde taal. De aanwezigheid in de taal C++ bewijst dat het kan.
Weer zo'n boeind en kansloos discussie punt ;) . Er zijn mensen die de aanwezigheid van multiple inheritance van implementatie in C++ juist een bewijs vinden dat het beter maar niet in een taal kan worden opgenomen ;) .
Ik ben absoluut tegen het gebruiken van ';' als statement seperator in plaats van statement terminator en ik dacht dat we er als programmeurs met z'n allen nu ook wel een keer over uit waren dat dat niet handig is.
Nee dus ;) . Alhoewel ik weinig echt tegen heb op de ";" als afsluiting van een statement, vind ik de ";" als sequentiele compositie van statements conceptueel een stuk fraaier.

Ik programmeer op dit moment voornamelijk in twee talen: Stratego en Java. In Stratego is de ; de sequentiele compositie van een strategie, in Java is het de afsluiting van een statement (eigenlijk niet, maar goed ...). Het gebeurt mij eigenlijk nooit dat ik in Stratego een ; teveel zet, maar dat kan ook komen omdat de taal een zeer duidelijke andere aard heeft.
Soultaker over geparametriseerde types
Nog even ter vergelijking: In een object georienteerde taal met geparameterizeerde typen (waar dus ook Generic Java en binnekort C# onder vallen) zou het ongeveer zou kunnen:
code:
1
public <N extends Numeral> N add(N n1, N n2);

Het probleem is alleen de verdere implementatie aangezien + niet werkt op objecten ;) (behalve als suiker op Strings). Voor andere situaties kan dit uiteraard wel goed gaan, zoals bijvoorbeeld bij deze map methode (niet bepaald een ideaal voorbeeld om OO fanaten te winnen voor geparameterizeerde typen ;) ):

code:
1
2
3
4
5
6
7
8
9
10
  public <A, R, E extends A> List<R>  map(Function<A, R> function, List<E> list) {
    List<R> result = new ArrayList<R>(list.size());

    Iterator<E> iterator = list.iterator();
    while(iterator.hasNext()) {
      result.add(function.apply(iterator.next()));
    }

    return result;
  }

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


  • tomato
  • Registratie: November 1999
  • Niet online
Soultaker schreef op 25 augustus 2002 @ 18:59:
Geen van beiden; je krijgt een compile-time error
Python lost dit anders op, daar worden bij multiple inheritance attributes en methods die niet gevonden in de baseclasses van links naar rechts gezocht:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A:
    def __init__(self):
        print 'papa A'
    def wieBenIk(self):
        print 'papa A'

class B:
    def __init__(self):
        print 'papa B'
    def wieBenIk(self):
        print 'papa B'

class C(A,B):
    def __init__(self):
        print 'kindje C'

x = A()
x = B()
x = C()
x.wieBenIk()

Geeft:
code:
1
2
3
4
5
# python mi.py
papa A
papa B
kindje C
papa A

Wanneer een method of attribute niet in C gevonden kan worden, wordt er depth-first, left-to-right in de baseclasses van C gezocht. Dus eerst in A, dan in baseclasses van A, etc.

  • Soultaker
  • Registratie: September 2000
  • Nu online
mbravenboer schreef op 25 augustus 2002 @ 20:04:
Ach, dan kunnen we heel lang gaan discussieren over er in een taal onderscheid moet zijn tussen objecten en pointers/references :+ . Kansloze discussie uiteraard.
Zonder duidelijk doel kan die discussie inderdaad nergens toe leiden. Het ging me er vooral om dat op basis van het ontbreken van onderscheid tussen objecten en references besloten werd dat er onderscheid moest zijn tussen deep/shallow copy en comparison operators.

Aangezien het om language features in het algemeen gaat (zonder dus van een specifieke taal uit te gaan, al wordt er aardig uit het object-georienteerde vaatje getapt) is zo'n redenering niet houdbaar.
Er zijn mensen die de aanwezigheid van multiple inheritance van implementatie in C++ juist een bewijs vinden dat het beter maar niet in een taal kan worden opgenomen ;) .
Ook dit is weer iets wat van je doelstelling afhangt. Als je een taal eenvoudig wilt houden, kun je er misschien op tegen zijn. Inderdaad kunnen veel problemen wel opgelost worden zonder multiple inheritance, maar datzelfde kan gezegd worden van geparametriseerde 'dingen' (methoden, klassen, functies).

Geen van beiden zijn in Java geimplementeerd, beiden wel in C++. Het is niet verwonderlijk dat een verschil in doelstelling ook een verschil in keuzen van taaleigenschappen tot gevolg heeft. Dat een feature voor een bepaalde doelstelling niet wenselijk is, betekent niet dat het voor een andere doelstelling niet zeer geschikt kan zijn.
Alhoewel ik weinig echt tegen heb op de ";" als afsluiting van een statement, vind ik de ";" als sequentiele compositie van statements conceptueel een stuk fraaier.
Het grootste bezwaar is het typen/editen van je code: je kunt met een statement separator niet makkelijk stukken code copy pasten en verplaatsen, omdat er soms wel en soms niet een puntkomma op 't eind staat. Conceptueel kan het wel kloppen, maar het is naar mijn idee onzinnig om de inhoud van regel X te laten afhangen van het toevallige feit of er nog ergens verderop nog wel of niet een ander statement staat. Vanuit de imperatieve zienswijze staat een statement op zichzelf; als ik een statement toevoeg, zou ik geen vorige statements hoeven wijzigen om de code weer geldig te krijgen.

Ik ben het echter met je eens dat je de ";" ook kan zien als een operator die resulterende staat van het ene statement in het volgende statement invoert (om een soort "monad passing" te introduceren), maar dan kun je de laatste ";" in een blok ook wel zien als een soort terminator-variant hierop, die wel invoer accepteert maar geen uitvoer genereert (aangezien 'ie maar op een enkele expressie wordt toegepast).

Als je 't zo bekijkt is jou voorbeeld ook goed te 'verklaren'. Als a, b en c expressies zijn, heeft "a; b; c" heeft als waarde het resultaat van de statements a, b en c (in die volgorde). "a; b; c ;" heeft echter geen resultaat (en kan dus niet als expressie gebruikt worden) aangezien de laatste ";" geen resultaat oplevert.
Voor andere situaties kan dit uiteraard wel goed gaan, zoals bijvoorbeeld bij deze map methode (niet bepaald een ideaal voorbeeld om OO fanaten te winnen voor geparameterizeerde typen ;) ):
Prachtige code, als je 't mij vraagt! Het is praktisch onmogelijk om zo'n methode fout te gebruiken (en dus at runtime problemen te krijgen).

Overigens, bij zulke constructies is naar mijn mening type coersion (waarbij automatisch wordt bepaald welke instantie van het geparametriseerde 'ding' gewenst is) onontbeerlijk. Het is immers wel prettig om "map(f, lijst)" te schrijven, maar als je "map<MijnEigenKlasse,MijnAndereKlasse,MijnDerivedKlasse>(f, lijst)" moet schrijven, is de lol er snel van af.

Om het nog erger te maken, kan ik me voorstellen dat je 'map' wilt parametriseren met het soort lijst.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
Soultaker: Het ging me er vooral om dat op basis van het ontbreken van onderscheid tussen objecten en references besloten werd dat er onderscheid moest zijn tussen deep/shallow copy en comparison operators.
Zeker, dat vind ik eigenlijk ook best wel een aardig punt (maar mijn afkeer van syntax voor pointers naar objecten weerhouden me van te groot enthousiasme ;) ) .
Prachtige code, als je 't mij vraagt! Het is praktisch onmogelijk om zo'n methode fout te gebruiken (en dus at runtime problemen te krijgen).
Leuk he :) . Ik gebruik hem nog regelmatig ook, net als veel andere functionele constructies. Ik heb ook nog een fold liggen volgens mij, maar die gebruik ik eigenlijk niet erg vaak bij OO programmeren (wel in Stratego).
Overigens, bij zulke constructies is naar mijn mening type coersion (waarbij automatisch wordt bepaald welke instantie van het geparametriseerde 'ding' gewenst is) onontbeerlijk.
Inderdaad, dat heb ik zelf ook al ondervonden tijdens het werken met Generics in Java. Bij geparameterizeerde methoden wordt de parameter altijd bepaalt op basis van de argumenten van de methode en is het dus niet nodig om parameters op te geven. Dit werkt erg prettig en zo werkt dus ook de methode hierboven.

Helaas werkt dit niet voor geparameterizeerde klassen en als je een constructor gebruikt moet je daarom altijd de parameters opgeven. Vaak is dit eigenlijk niet nodig omdat de parameters op basis van de argumenten van de constructor bepaald zou kunnen worden. Daarom maak ik in dergelijke gevallen vaak geparameterizeerde static methoden die de constructor aanroepen. Je hoeft dan de parameters niet op te geven...

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


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Het besta qua taal wat mij overkomen is de laatste tijd zijn properties:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TAap = class
private
  FA: Integer;
  FB: String;
  function Get(Index: Integer): string;
  function GetC: String;
  function GetValue(const Name: string): string;
  procedure Put(Index: Integer; const Value: string);
  procedure SetB(const Value: String);
  procedure SetValue(const Name, Value: string);
public
  property A: Integer read FA write FA;
  property B: String read FB write SetB;
  property C: String read GetC;
  property Values[const Name: string]: string read GetValue write SetValue;
  property Strings[Index: Integer]: string read Get write Put; default;
end;

Voor de mensen die deze classe gebruiken zien de properties eruit als variablen en je schermt ze dus af van de getters en setter methoden.

Dit wordt al jaren gebruikt in Delphi en BCB, maar nu wordt het ook gebruikt in .Net.

[ Voor 0% gewijzigd door LordLarry op 25-08-2002 21:53 . Reden: code tag ]

We adore chaos because we like to restore order - M.C. Escher


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Ik ben weer een weekend weg, en dan komen mesen aanzetten met ;)
mbravenboer schreef op 25 augustus 2002 @ 15:01:
Even een rijtje punten, waar echter nog zeker een selectie procedure op los moet worden gelaten ;) .

1) Zoveel mogelijk taal constructies expressies zijn en in het algemeen het aantal non-terminals in de taal beperkt is. Ik denk tov Java dan aan if-then-else statements en try-catch statements.
Mee eens! ?: rulez. :) Goed, je code wordt niet echt leesbaar als je alle if-else vervangt door ?: maar dat heet job security.
Assignments zou ik echter juist weer niet als expressies willen zien en in ruil daarvoor zou ik expressie-blocken wileln zien. Een expressie block is het volgende:

code:
1
"{" Stm Expr "}" -> Expr


In woorden: een aantal statements, gevolgd door een expressie is een expressie. Een assignment als expressie moet dan vervangen worden door deze constructie:

code:
1
{ x := 5; x}
Dat werkt alleen (efficient) als de lvalue opnieuw kan worden bepaald zonder dure operatie. Neem b.v. een C++ std::map ( associatieve array), de index operator ( operator[]( Key ) ) is O(logN). map["hello"] mag je best ""world" aan toekennen. Als je dat een expressie laat wezen hoef je niet opnieuw de lookup van "hello" te doen. Dus ik ben nog niet overtuigd dat dit overall een verbetering is.
De 'blocks' onder if-then-else statements en try-catch statements mogen ook dergelijke expressie blocken zijn, waardoor je het volgende zou kunnen doen:

code:
1
2
3
4
5
6
7
int x = try{
             doSomethingDangerous()
         } catch( Exception exc) {
             13
         }

int x = if ( y < 3) {  y * 4  } else {  y * 3 }
Die's mooi. Misschien kunnen we'm beter try?(expr1):expr2 noemen, waarbij expr1 altijd wordt geevalueerd en expr2 alleen als expr1 throw'ed.
Bodies van functies zouden bijvoorbeeld ook expressie-blocken zijn:
code:
1
2
3
4
5
public int doSomething() {
    int result;
    ......
    result
}
Het nut hievan ontgaat me.
2) Er geen onderscheid is tussen primitieven en objecten. Het onderscheid tussen primitieven en objecten is een optimalisatie detail waar je de programmeur niet lastig mee hoeft te vallen. Compiler technologie en de snelheid van computers is zo ver gevorderd dat een compiler lekker zelf kan gaan uitzoeken wanneer er primitieven gebruikt kunnen worden. Liefst moet dit gedrag ook nog doorgetrokken worden naar alle objecten en niet alleen naar de zaken die nu al primitief zijn. Overigens zie ik dus liever een andere oplossing dan in C#, waar er een scheiding is tussen klassen en value-types en primitieve waarden gebruikt kunnen worden als objecten via auto-boxing. Dit zijn (logische) lapmiddelen en geen echte oplossing van het probleem.
Mee eens. Maar als ik kijk naar C++ is dat feitelijk daar al het geval. Er is niet eens een object equivalent aan de "primitieve" int.
3) Er zou een aparte taal-constructie moeten zijn om aan te geven dat een bepaalde variabele de waarde null mag hebben of niet. Ik doel hiermee uiteraard op het ? van Nice.
Dit is een bijzonder geval van een geparmeteriseerd type. Optional<T> heeft waardes { null, { waardes(T) } }. Het voordeel hiervan is dat Optional<Optional<T> > gebruikt kan worden om twee singuliere waarden met T te associeren.
5) Overflow checks en checked conversions zoals in C#
6) Array index checks
Nee. Een snelle taal zonder checks kun je veilig maken door checks toe te voegen. Andersom gaat niet. Veiligheid kan beter bereikt worden door de onveilige constructies een lange naam te geven (denk C++ reinterpret_cast< > ) en de veilige library constructies een kortere naam.
7) Syntaxtische suiker voor lijsten, tuples etc. Eventueel zou het ook heel fraai zijn als je zelf naar behoefte syntaxtische suiker kan toevoegen (wat veel verder gaat dan alleen operator overloading), maar dit gaat wellicht wat ver voor een mainstream taal.
Dat is commercieel onhaalbaar. Er is binnen de C++ commissie (uiteraard) hierover gefilosofeerd, maar de kosten om zoiets in een commerciele compiler toe te voegen zijn onhaalbaar hoog cq. deze taal/compiler wordt links en recht ingehaald door andere talen/compilers waar het geld besteed is aan nuttigere features.
9) Laten we nu eindelijk eens dapper genoeg zijn om assignments als := te introduceren in een mainstream taal. Inhoudelijke vergelijking (.equals) kan = worden en pointer vergelijk kan == worden.
De winst? Ik weet in elk geval dat een verschil tussen = en == onzinnig is. Neem een generiek algoritme als find. Gegeven een collectie van Ts, coll[0] tot coll[N] en een gezochte waarde t. Nu is find een uniform algoritme ( while (! (coll[i] == t ) )++i; return i; ) maar met separate =/== heb je twee versies van dit algoritme nodig. Daarentegen is het verschil tussen *i==*j en i==j visueel duidelijk; met =/== is dat veel minder.
10) Betere pattern-matching mogelijkheden: methode declaraties zouden ook patronen moeten kunnen bevatten, waardoor je methoden kan implementeren in varianten voor verschillende mogelijke patronen. Op dit moment bieden de meeste talen alleen een soort pattern-matching op het type van de eerste of verdere parameters. Je kan methoden overloaden, waardoor je een methode op verschillende manieren kan implementeren voor verschillende typen. Waarom niet verder gaan en krachtige pattern-matching op de inhoud van objecten invoeren? Dit heeft ook een beetje te maken met multi-methods, maar gaat eigenlijk nog verder.
Ten eerste omdat dit slecht samen gaat met generieke functies - het vinden van een overload wordt rampzalig moeilijk als elke template instantiatie een pattern oplevert ipv een enkele functie - en ten tweede omdat forwarder functies een redelijk deel van deze capaciteiten kunnen leveren.
12) altijd de toegang van een methode/klasse/veld aangeven. Daarom moet er ook een aparte modifier komen voor package access.
Voor package access is eerst een betere package/module structure nodig. Voor de rest is het een overbodig feature omdat er acuut een editor komt die de herhaalde public:/private: access specifiers voor je insert. De duidelijkheid wordt er IMO ook niet al te veel door verhoogd.
14) Waarom moet je een constructor de naam van klasse geven :? Noem hem gewoon 'constructor'. Veel duidelijker.
Tsja, geval van zelf opgelegde beperking van C++ (minder nieuwe keywords = betere compabiliteit met C) die zeker niet gevolgd had moeten worden in compleet nieuwe talen. Dit is duidelijk een gemiste kans om ten opzichte van C++ te verbeteren.
16) Geen assigment aan parameters: parameters zijn standaard final
Waarom? Laat de compiler de consequenties ervan bepalen. Ik mis eerlijk gezegd het probleem.
17) Serie aanroepen op een object: in de Java library zie je dat steeds meer methoden 'this' gaan opleveren zodat er gelijk weer een methode kan worden aangeroepen op het resultaat. Dit werkt sterk vervuilend omdat je de documentatie moet raadplegen om te zien of er ook daadwerkelijk 'this' of een nieuw object wordt opgeleverd. Daarom moet er een taal constructie komen die het mogelijk maakt om meerdere methoden achter elkaar aan te roepen op een object. Voorbeeldje:
code:
1
  std::cout << "Hello" << ", world" << std::endl;

Kortom, C++ heeft het al 10 jaar. Inmiddels is dit zo ingeburgerd dat niemand zich realiseert dat er in theorie ook een ander object kan worden terug gegeven.
18) Entry point van een applicatie sterk verbeteren: static main eruit en vervangen door een interface Application of iets dergelijks die je moet implementeren.
int main( std::vector<std::string> ); bijvoorbeeld. Niet alles is een object.
19) ";" liever als scheidings teken tussen statements dan als afsluiting van een statement ...
Programmeurs maken meer fouten met scheidings tekens dan met statement terminators;dit is 20 (dacht ik) jaar geleden uitgezocht.
20) Een taal waarin (eventueel met behulp van semantische analyse) de betekenis van elke constructie kan worden bepaald zonder daarbij externe bestanden of libraries te moeten raadplegen. Dit is uitermate belangrijk voor meta-tools rond een taal zoals tools die helpen bij refactoring. Dit zijn echter hele vervelende zaken die erg veel vragen van meta-tools. Hier is duidelijk niet over nagedacht, anders was er vast een andere constructie gekozen. Er wordt vaak gezegd dat C niet context-vrij te parsen is (wat klopt), maar ik zou dit eigenlijk willen doortrekken naar Java. Vanwege de situatie hierboven is er namelijk een "ambigious name" opgenomen in de grammatica van Java. Lijkt mij niet echt de oplossing.
Klopt. Stroustrup is in dit verband bezig met XDR, wat een dermate simpele representatie van C++ programma's is dat elke HBO'er in z'n eerste jaar de XDR code kan parsen. XDR is makkelijk door compilers te genereren, en ook makkelijk terug te converteren naar C++. Voor Java zou zo'n dergelijke representatie taal mogelijk nog makkelijker en effectiever zijn.

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


  • Juup
  • Registratie: Februari 2000
  • Niet online
mbravenboer schreef op 25 augustus 2002 @ 15:01:
9) Laten we nu eindelijk eens dapper genoeg zijn om assignments als := te introduceren in een mainstream taal. Inhoudelijke vergelijking (.equals) kan = worden en pointer vergelijk kan == worden.
Maak er dan meteen een <= van.

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Juup schreef op 26 augustus 2002 @ 14:09:
[...]

Maak er dan meteen een <= van.
Nee, laten we dat aub niet doen. Dan hebben we weer een assignment probleem bij vergelijkingen.

if (Test=3) // Assignment
if (Test==3) // Vergelijking
if (Test<=3) // Vergelijking
en jij stelt dus voor
if (Test<=3) // Assigment
?!

We adore chaos because we like to restore order - M.C. Escher


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11 01:34
Mee eens! ?: rulez. Goed, je code wordt niet echt leesbaar als je alle if-else vervangt door ?: maar dat heet job security.
Eerlijk gezegd dacht ik niet gelijk aan het ietwat cryptische ?: , maar de echte syntax is een detail waar je later lang over kunt discussieren. Belangrijkste punt is dat er geen verschil zou moeten zijn tussen een conditionele expressie en een conditionele expressie en zeker niet in de syntax.
Dat werkt alleen (efficient) als de lvalue opnieuw kan worden bepaald zonder dure operatie. Dus ik ben nog niet overtuigd dat dit overall een verbetering is.
De efficientie hiervan is inderdaad een goed punt, maar voor vele gevallen (zoals deze simpele assignment) is dit geen enkel probleem en kan de compiler deze optimalisatie uitstekend zelf uitvoeren.
Die's mooi. Misschien kunnen we'm beter try?(expr1):expr2 noemen, waarbij expr1 altijd wordt geevalueerd en expr2 alleen als expr1 throw'ed.
Die try-catch is inderdaad erg verbose, maar ik ben ook wel bang voor een te cryptische syntax. In Stratego combineer je twee strategien met de <+ operator als je de linker strategie voorrang wilt geven: in "s1 <+ s2" zal er eerst gekozen worden voor s1 en pas als deze faalt zal s2 worden gekozen. Deze syntax staat mij eigenlijk wel aan.

code:
1
int x = doSomethingDangerous() <+ 13


Probleem is alleen dat hier geen onderscheid meer is tussen verschillende vormen van exceptions. Juist de introductie hiervan zorgt voor onduidelijke code.
[expressie blocken als function bodies] Het nut hievan ontgaat me.
Mij ook :+ . Het zou goed passen in de filosofie van expressie blocken en waarom dus een andere taal-constructie gebruiken voor iets wat in wezen gezien kan worden als een expressie-block?
Dit is een bijzonder geval van een geparmeteriseerd type. Optional<T> heeft waardes { null, { waardes(T) } }. Het voordeel hiervan is dat Optional<Optional<T> > gebruikt kan worden om twee singuliere waarden met T te associeren.
Inderdaad, zo zie je het ook terug in veel functioneel achtige talen. In Stratego bijvoorbeeld ook:

code:
1
2
Some: a -> Option(a)
None: Option(a)


Deze vorm van werken is echter een vrij verbose manier van werken. Bovendien kan je alleen maar door statements controleren dat T niet alsnog de waarde null heeft. Bovendien is er helemaal geen methode om aan te geven dat iets niet null mag zijn. Een compacte syntax zoals in Nice vind ik buitengewoon fraai en een hele waardevolle toevoeging.
[checks]Nee. Een snelle taal zonder checks kun je veilig maken door checks toe te voegen. Andersom gaat niet.
Ach, over het belang van dergelijke features kan je heel lang discussieren ;) . Ik zou in het voordeel van dergelijke checks kunnen aanvoeren dat ik gevallen (of dit nu vaak of zelden is, zal sterk per applicatie verschillen) bounds checks geelimineerd kunnen worden door de compiler.
Dat is commercieel onhaalbaar. Er is binnen de C++ commissie (uiteraard) hierover gefilosofeerd, maar de kosten om zoiets in een commerciele compiler toe te voegen zijn onhaalbaar hoog cq. deze taal/compiler wordt links en recht ingehaald door andere talen/compilers waar het geld besteed is aan nuttigere features.
Tja, ook daar valt weer flink over te discussieren. Een deel van de compactheid van veel functioneel achtige talen is toch wel terug te voeren op de syntax voor lijsten. Als ik in Stratego wil controleren of het eerste en het laatste element van een lijst aan bepaalde voorwaarde 's' moet voldoen schrijf ik:

code:
1
[<s> | <last; x>]


In een taal als Java ben je toch al snel een aardig aantal regels kwijt om hetzelfde te doen. Dit komt uiteraard niet alleen door de lijst-syntax, maar voor een deel wel. Een ingebouwde syntax voor lijsten en tuples zou ook een algebraische manier van werken bevorderen, wat wellicht de duidelijkheid en correctheid van veel applicaties ten goede zou komen.

Ik begrijp je argument uiteraard verder wel en helaas heb je ook wel gelijk ;) .
[:=] De winst?
Het is grappig om te zien dat in vrijwel elk illustratief taaltje := wordt gebruikt ipv = voor assignment. Dit wordt ervaren als duidelijker omdat = snel wordt geassocieerd met equivalentie. Deze discussie of := gebruikt zou moeten worden voor assignment, staat eigenlijk los van verschillen tussen =, == , .equals enz... Voordeel van het gebruik van := is dat de = vrijkomt voor de pool van equivalentie operatoren ;) .
Ten eerste omdat dit slecht samen gaat met generieke functies - het vinden van een overload wordt rampzalig moeilijk als elke template instantiatie een pattern oplevert ipv een enkele functie - en ten tweede omdat forwarder functies een redelijk deel van deze capaciteiten kunnen leveren.
Het conflict is duidelijk: ik wil functionalit die abstraheert, ook al gaat dit ten koste van de performance. Jij wilt gewoon een efficientie, compacte en minimale taal zonder flauwekul. Voor beide ideeen valt denk ik wel het een en ander te zeggen. Leukere pattern matching zie je op dit moment vrijwel alleen nog maar in functionele en andere declaratievere talen. Ik denk dat de introductie van dergelijke functionaliteit in imperatieve talen ook geen kwaad zou kunnen.
Tsja, geval van zelf opgelegde beperking van C++ (minder nieuwe keywords = betere compabiliteit met C) die zeker niet gevolgd had moeten worden in compleet nieuwe talen. Dit is duidelijk een gemiste kans om ten opzichte van C++ te verbeteren.
Zeker, helemaal mee eens... Helaas zie je nog veel van dergelijke naweeen terug in Java en C#: neem bijvoorbeeld eens de ";" als type-dec die de beste C++ programmeur zo enorm zou helpen bij het programmeren in Java |:( . Laten we het nog maar niet hebben over alle array varianten bij variabelen en methode delcaraties in Java.
[final parameters] Waarom? Laat de compiler de consequenties ervan bepalen. Ik mis eerlijk gezegd het probleem.
Zie de refactoring "Remove Assignments to Parameters" op blz 131 in het boek van Martin Fowler. De redenatie daar is de onduidelijkheid tussen pass by value en pass by reference. Verder is het duidelijker als een parameter gedurende de gehele methode dezelfde waarde behoudt: het is iets wat je meegeeft, niet iets wat je gebruikt om mee te rekenen.
Klopt. Stroustrup is in dit verband bezig met XDR, wat een dermate simpele representatie van C++ programma's is dat elke HBO'er in z'n eerste jaar de XDR code kan parsen. XDR is makkelijk door compilers te genereren, en ook makkelijk terug te converteren naar C++. Voor Java zou zo'n dergelijke representatie taal mogelijk nog makkelijker en effectiever zijn.
Hum, dat klinkt leuk. Ik heb nog nooit van XDR gehoord. Ik zal eens rondkijken op het web of ik iets leuks kan vinden. Voor Java is het inderdaad vrij eenvoudig om een duidelijke subset te maken. Ik ben zelf de laatste tijd veel met meta-tools bezig en kom hier steeds dergelijke problemen tegen. Het verbaast mij dat met dergelijke problemen niet beter rekening is gehouden bij het ontwerp van de moderne talen. Zeker bij Java is het in feite rampzalig...

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

Pagina: 1