Toon posts:

[algemeen] Enum gedachten*

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

Verwijderd

Topicstarter
In de meeste talen heb je enumeraties. Vaak kun je hier ook nog een integer-waarde aan geven. Intern vertaald de compiler dit ook naar integer waarden, puur om performance. De enum-token is er voor de programmeur om de boel leesbaar te houden. Tof.

Maar tegenwoordig met internet en XML is het tekst wat de klok slaat. Maw: je kunt die enum wel naar een integer waarde casten en die dan in je HTML vrotten, maar dat maakt het er niet begrijpelijk op.

Je voelt hem al aankomen. Een enum-entry zou geconverteerd moeten kunnen worden naar een string! En dan moet de compiler je dus helpen de token naar een literal om te zetten. Andersom zou ook kunnen. Het volgende pseudo code illustreert dit wel:
code:
1
2
3
4
5
6
7
8
typedef enum { ja, nee, misschien } Antwoord;
Antwoord eAntwoord;
string sAntwoord;

eAntwoord=nee;
sAntwoord=(string)eAntwoord; //sAntwoord bevat nu de string 'nee'
...
eAntwoord=(Antwoord)sAntwoord; //eAntwoord bevat nu de enum waarde nee

Mijn vraag aan jullie: Wat vinden jullie hiervan? Zien jullie beren op de weg? Waarom hebben ze dit niet in C# gestopt?

OK, ik zie wel een beer, het terugcasten van string naar enum. Wordt het undefined, een run-time error, moet er een check komen of het wel een geldige enum-waarde is?

Maar het zou wel top-handig zijn!

___________
*D Het onderwerp is onderwerp aan verandering.

Verwijderd

Met delphi kan dat al :) Beide kanten op, als undefined dan wordt het -1. [Enums beginnen in Delphi altijd op 0]

Maar ik heb het nog nooit gebruikt. Kan me wel voorstellen dat het handig kan zijn.

  • Orphix
  • Registratie: Februari 2000
  • Niet online
Tja ik vind het idd geen slecht idee, dit zou op veel plekken ook al tijdens compile time kunnen gebeuren.

Ik kan me wel voorstellen waarom dit er niet in zit. enum's zijn voor de programmeur als hulpmiddel bedoelt, niet voor de representatie naar de gebruiker toe. Je houdt dat zonder deze constructie beter gescheiden. Bovendien kan bv in C++ je zoiets ook wel vrij gemakkelijk maken, mbv een map. Aan het begin van je programma zet je in die map (of hash) voor elke enum waarde een string, en die kan je dan makkelijk oproepen later in je code. Dit heeft als voordeel dat je later de string nog eens kan aanpassen zonder jouw code (en die van anderen) die op de enum leunt aan te passen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Doekman: In de meeste talen heb je enumeraties.
Zoals je vast weer in Java bijvoorbeeld niet ;) . In Java wordt je aangeraden bijvoorbeeld het volgende te gebruiken:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.pandoramix.gui;

public class CompassDirection
{
    public static final CompassDirection NORTH  = new CompassDirection("North");
    public static final CompassDirection EAST   = new CompassDirection("East");
    public static final CompassDirection SOUTH  = new CompassDirection("South");
    public static final CompassDirection WEST   = new CompassDirection("West");
    public static final CompassDirection CENTER = new CompassDirection("Center");

    private String _description;

    protected CompassDirection(String description)
    {
      super();
    }

    public String toString()
    {
      return _description;
    }
}

Helaas gebruikt lang niet iedereen dit en zie je veel zogenaamde enumeraties met behulp van constante integers. Als je me een beetje kent zul je begrijpen dat ik dat verschrikkelijk vind :+ .

De bovenstaande methode is wat veel syntax voor eenvoudig werk, maar zodra je in wat leukere voorbeelden terecht komt wordt deze oplossing al snel erg makkelijk: er is geen aparte constructie voor enumeraties en dus kan je alles met een enum doen wat je ook met een gewoon object kunt doen. Jowu voorstel is een typisch voorbeeld: je kunt er methoden aan toe voegen die allerlei zaken doen of gegevens opleveren over de enum. Wellicht dat een ander namelijk weer graag iets anders met een enum wil doen.

Je wilt ook vaak aan de hand van een enum switchen. Een switch is echter een niet al te geliefde operatie in een goed OO design. Switch duit op gevalsonderscheid, wat op veel verschillende plaatsen kan voorkomen. Dergelijke constructies wil je liever oplossen met polymorphisme. Daarvoor is het handig als enums niet een simpel systeem is, maar gewoon een volledig object met alle functionaliteit die daar omheen hangt.

De performance van deze implementatie is ook nog wel aardig: objecten worden maar 1 maal aangemaakt, dus dat is geen groot punt. Als je properties hebt (zoals in C#) kan je ze zelfs nog lazy maken. Prachtig allemaal :) . Bovendien kan je simpele == vergelijking gebruiken om waarden te vergelijken. Dat is dus ook behoorlijk snel.
Vaak kun je hier ook nog een integer-waarde aan even.
In C# kan je veel primitieven gebruiken: byte, sbyte, short, ushort, int, uint, long en ulong. Helaas voor jou: idd geen string ;) .
Je voelt hem al aankomen. Een enum-entry zou geconverteerd moeten kunnen worden naar een string! En dan moet de compiler je dus helpen de token naar een literal om te zetten.
Als je enums in je taal hebt is dat inderdaad wel een aardig idee :) . Je geeft zelf al wel het probleem aan: andersom moet ook kunnen en met strings gaat dat natuurlijk wat minder makkelijk dan met ints :) . Bovendien moet je natuurlijk duidelijk beslissen wat er gebeurt als je een verkeerde waarde opgeeft, maar dat is met de huidige oplossingen van ints etc ook al het geval :) .
Mijn vraag aan jullie: Wat vinden jullie hiervan?
Leuk, maar gevaarlijk: het is nogal een detail aspect van een taal en ik ben bang dat je dan al snel een explosie aan wensen krijgt: naam van een variabele, naam van een methode, regelnummer, source-file, aantal enums, aantal methoden enzovoorts.... Op zich stuk voor stuk allemaal weleens interessant, maar je moet goed uitkijken dat je taal nog steeds logisch in elkaar blijft zitten en niet al te complex wordt :) . Uiteraard is dit niet zo'n ingewikkeld voorbeeld en met casts is het wel aardig uit te drukken, maar alles bij elkaar kan het wel een aardige toestand worden en je moet er dus goed over nadenken dat alles logisch in elkaar blijft steken :) .
Waarom hebben ze dit niet in C# gestopt?
Goede vraag :) . Als je enums hebt is wel aardig, zeker in een platform als .NET. Maar ik betwijfel dus sowieso het nu van enums, maar goed dat is een ander topic waar je heel lang over kunt kletsen :) .
moet er een check komen of het wel een geldige enum-waarde is?
Tja, dat lijkt mij sowieso een goed idee :) .

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


Verwijderd

Topicstarter
Op donderdag 31 januari 2002 23:42 schreef DiFool het volgende:
Met delphi kan dat al :) Beide kanten op, als undefined dan wordt het -1. [Enums beginnen in Delphi altijd op 0]
Ik wist het wel, Object-Pascal rulezz (vroeger veel gedaan in turbo pascal)
Op donderdag 31 januari 2002 23:59 schreef mbravenboer het volgende:
Zoals je vast weer in Java bijvoorbeeld niet ;)
Ja, ik ben er al eens op gewezen ;). Het zit trouwens ook niet in Javascript.
Helaas gebruikt lang niet iedereen dit en zie je veel zogenaamde enumeraties met behulp van constante integers. Als je me een beetje kent zul je begrijpen dat ik dat verschrikkelijk vind :+ .
Yes, indeed. Alsof een enumeratie een lijst van integers is.
Je wilt ook vaak aan de hand van een enum switchen. Een switch is echter een niet al te geliefde operatie in een goed OO design. Switch duit op gevalsonderscheid, wat op veel verschillende plaatsen kan voorkomen. Dergelijke constructies wil je liever oplossen met polymorphisme. Daarvoor is het handig als enums niet een simpel systeem is, maar gewoon een volledig object met alle functionaliteit die daar omheen hangt.
Hmm, even denken, waar gebruik ik enums voor:
  1. Toestand (bekend van Eindige automaat, in UML hebben ze ook zoiets)
  2. Veld-aanduiding bij lijsten (maar dat kan nog niet met ADO, omdat er geen enum-integratie is met databases :()
  3. Opties (als een eigenschap meerdere waarden kan aannemen)
Hmm, bij optie 1 wil ik wel graag enums houden. Bij optie 2 hebben we geen enum-integratie nodig, maar object integratie (maw: de database moet een interface exporteren voor velden en tabellen, oo/rel-database, hmmm, nieuwe discussie). En 3, ik wil nog steeds de Set operator van Delphi in alle talen.
De performance [...] ook behoorlijk snel.
Maar veel typewerk, programmeurs zijn lui. Als het af is werkt het wel strak.
Leuk, maar gevaarlijk: het is nogal een detail aspect van een taal en ik ben bang dat je dan al snel een explosie aan wensen krijgt:
Inderdaad. En wordt het ook zo gebruikt, als het bedoeld is...

Maar over je java-enum-construct: het is weinig abstract, en dus minder leesbaar. Zou een soort short-cut hiervoor niet handiger zijn?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Doekman: Maar over je java-enum-construct: het is weinig abstract, en dus minder leesbaar. Zou een soort short-cut hiervoor niet handiger zijn?
Tja, het probleem is dan je keuzen moeten maken: als je shortuts gaat toestaan krijg je steeds meer constructies in je taal, wat dus zeker niet de doelstelling van Java is :) .

Het voorbeeld is ook wat lang door mijn lange klasse-naam en omdat ik ook nog een methode heb toegevoegd. Het kan nogal wel een stukje duidelijker. Voordeel van deze oplossing is dat je type-safe enumeraties hebt, je enumerates ook nog uit kan breiden met methoden en je allerlei varianten kunt toepassen (polymorphisme, uitbreidingen in sub-classes enzvoorts).

Ik ben er dus wel tevreden mee :) . Helaas geeft de Java api alleen het verkeerde voorbeeld. In de eerste Java versies zijn veel grove fouten gemaakt, die nu lastig ongedaan te maken zijn.

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


Verwijderd

Op donderdag 31 januari 2002 23:42 schreef DiFool het volgende:
Met delphi kan dat al :) Beide kanten op, als undefined dan wordt het -1. [Enums beginnen in Delphi altijd op 0]

Maar ik heb het nog nooit gebruikt. Kan me wel voorstellen dat het handig kan zijn.
Hoe kan ik dat regelen in Delphi dan? Ik ken alleen het volgende:
code:
1
2
3
4
5
6
7
8
9
10
type
  TAntwoord = (taJa, taNee, taMisschien);

const
  sAntwoord : Array[TAntwoord] of String = ('Ja', 'Nee', 'Misschien');

function GeefWaardeTerug(const Antwoord: TAntwoord): String;
begin
  Result := sAntwoord[Antwoord];
end;

Is bovengenoemde de enige manier of zijn er nog andere manieren? Want op deze manier kun je niet zo heel makkelijk terug.

Verwijderd

Dit is wel degelijk mogelijk in .NET :)
.Net is sterk getypeerd. Om fouten te voorkomen kun je aan een functie die een string verwacht ook geen object meer meegeven, waar (in java tenminste) automatisch toString() op aangeroepen wordt. Dit moet de programmeur nu specefiek duidelijk maken. Hetzelfde geld nu voor het parsen van een enum. Anders zou je vb style kunnen aanhouden:
int i = (int)"123";
maar: int i = Int32.Parse("123");
Hetzelfde geld voor enums, aangezien je opgegeven enum geen ingebouwde is, moet je ook nog eventjes casten naar de enum van je type.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;

namespace Tweakers
{
    public enum Direction { North, East, South, West };
    
    public class Test
    {
        public static void Main()
        {
            Console.WriteLine(Direction.North);
            Console.WriteLine(ParseDirection("East"));
        }

        public static Direction ParseDirection(String s)
        {
            return (Direction)Enum.Parse(typeof(Direction), s);
        }
    }

}

Bij opgeven van een ongeldige waarde krijg je netjes een Argument exception met "Arg_MustContainEnumInfo" in je schoot geworpen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
solar: Om fouten te voorkomen kun je aan een functie die een string verwacht ook geen object meer meegeven, waar (in java tenminste) automatisch toString() op aangeroepen wordt.
Die opmerking van Java klopt niet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
public class Test
{
    public static void main(String[] ps)
    {
      doSomething(new Test());
    }

    public static void doSomething(String s)
    {
  
    }
}

Compiler:
code:
1
2
3
4
5
martin@linux:~ > javac Test.java
Test.java:5: doSomething(java.lang.String) in Test cannot be applied to (Test)
      doSomething(new Test());
      ^
1 error

Alleen als je objecten in een optelling van Strings gebruikt (+ operaties dus) wordt automatisch toString aangeroepen.

Dat van die Enum parsen wist ik trouwens nog niet :) . Bedankt voor de tip :) .

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


Verwijderd

Topicstarter
Op vrijdag 01 februari 2002 13:44 schreef solar het volgende:
Dit is wel degelijk mogelijk in .NET :)
Eén woord: teGek :7

Verwijderd

hvdberg: Hoe kan ik dat regelen in Delphi dan? Ik ken alleen het volgende:
Zo:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
uses
  TypInfo;

type
  TAntwoord = (taJa, taNee, taMisschien);

procedure ShowTypeOf(const AString: string);
begin
  case TAntwoord(GetEnumValue(TypeInfo(TAntwoord), AString)) of
    taJa: ShowMessage('taJa');
    taNee: ShowMessage('taNee');
    taMisschien: ShowMessage('taMisschien');
  else
    ShowMessage('Bestaat niet');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  { Van enum -> string }
  ShowMessage(GetEnumName(TypeInfo(TAntwoord), Ord(taJa)));
  { van string -> enum }
  ShowTypeOf('hoi');
  ShowTypeOf('taJa');
  ShowTypeOf('TAJA');
end;

edit:

TypeInfo is compiler magic en geeft een pointer naar RTTI van TAntwoord.

Dit is dus vooral handig [nodig] om property editors te maken. Dus om bij een enum property een lijst met waarden te hebben.

Verwijderd

Op vrijdag 01 februari 2002 15:24 schreef DiFool het volgende:

[..]

Zo:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
uses
  TypInfo;

type
  TAntwoord = (taJa, taNee, taMisschien);

procedure ShowTypeOf(const AString: string);
begin
  case TAntwoord(GetEnumValue(TypeInfo(TAntwoord), AString)) of
    taJa: ShowMessage('taJa');
    taNee: ShowMessage('taNee');
    taMisschien: ShowMessage('taMisschien');
  else
    ShowMessage('Bestaat niet');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  { Van enum -> string }
  ShowMessage(GetEnumName(TypeInfo(TAntwoord), Ord(taJa)));
  { van string -> enum }
  ShowTypeOf('hoi');
  ShowTypeOf('taJa');
  ShowTypeOf('TAJA');
end;

edit:

TypeInfo is compiler magic en geeft een pointer naar RTTI van TAntwoord.

Dit is dus vooral handig [nodig] om property editors te maken. Dus om bij een enum property een lijst met waarden te hebben.
En bedankt! Werkt perfect.
Pagina: 1