August 10, 2004
On Tue, 10 Aug 2004 11:56:06 +0000 (UTC), Arcane Jill <Arcane_member@pathlink.com> wrote:
> In article <opschrxff75a2sq9@digitalmars.com>, Regan Heath says...
>
>>   //proposed method
>>   fooBar(THE|QUICK|BROWN|FOX|JUMPS|OVER|THE|LAZY|DOG);
>
> Would that work? I mean, I can see that:
>
> #    fooBar(THE);
>
> would work, since (assuming your proposed scheme) the compiler would be able to
> infer the type of the fooBar parameter. But as for
>
> #    fooBar(THE|QUICK|BROWN|FOX|JUMPS|OVER|THE|LAZY|DOG);
>
> I have to ask - what is the compile-time type of the expression:
>
> #    THE|QUICK|BROWN|FOX|JUMPS|OVER|THE|LAZY|DOG
>
> My guess is that the compile-time type of even the expression:
>
> #
> FooBarBaz.THE|FooBarBaz.QUICK|FooBarBaz.BROWN|FooBarBaz.FOX|FooBarBaz.JUMP|FooBarBaz.OVER|FooBarBaz.THE|FooBarBaz.LAZY|FooBarBaz.DOG
>
> is not actually FooBarBaz, but is in fact int. Does the | operator preserve the
> type of an enum? I'm not sure that it does.

Good question.. I think Walter is the only one who can really answer it, however, my tests show that you cannot pass an 'int' to a function expecting a 'FooBarBaz', but you can pass something like 'FooBarBaz.ONE|FooBarBaz.TWO'. In fact you can also cast and pass another enum type if you want.

enum FooBarBaz {
  ONE   = 0x1,
  TWO   = 0x2,
  THREE = 0x4,
  FOUR  = 0x8
}

enum BarBazFoo {
  ONE   = 0x8,
  TWO   = 0x4,
  THREE = 0x2,
  FOUR  = 0x1
}

void fooBar(FooBarBaz a) {
	printf("%x\n",a);
}

void main()
{
  int i = FooBarBaz.ONE|FooBarBaz.TWO;
  fooBar(i);  //function fooBar (FooBarBaz a) does not match argument types (int)
              //cannot implicitly convert expression i of type int to FooBarBaz
  fooBar(FooBarBaz.ONE|FooBarBaz.TWO);
  fooBar(cast(FooBarBaz)BarBazFoo.ONE|BarBazFoo.TWO);
}

> Arcane Jill
> (basically in support but with one or two niggling doubts).

Glad to see someone is thinking about how genreally 'nice' this would be without accusing me of being lazy.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 11, 2004
In article <opscjhxy015a2sq9@digitalmars.com>, Regan Heath says...

>Glad to see someone is thinking about how genreally 'nice' this would be without accusing me of being lazy.

I take pride in being lazy. When I was studying math at school, I was taught that math is all about being lazy, and that the very best mathematicians are the laziest of all. If you cou prove a theorem ONCE for (say) "rings", then you've proven it for reals, integers, whatever. There are parallels with OOP here - component re-use is all about being lazy. I also write libraries because I'm lazy (why write the same piece of code more than once?). I use Phobos routines because I'm lazy (why write a piece of code at all if someone else has done it for me?). I even write in D because I'm lazy (why invent my own brand new computer language when I can just use Walter's?). I dunno, but I guess those mad workaholic types just enjoy re-inventing the wheel all the time, or maybe they just get a buzz out of pressing keys on their keyboard?

Jill
(Lazy and proud of it)



August 11, 2004
In article <cfcgjg$4v6$1@digitaldaemon.com>, Arcane Jill says...
>
>In article <opscjhxy015a2sq9@digitalmars.com>, Regan Heath says...
>
>>Glad to see someone is thinking about how genreally 'nice' this would be without accusing me of being lazy.
>
>I take pride in being lazy.

and of course
"efficience is the smart lazy"
(better wording welcome)

Ant


August 11, 2004
Give the hardest job to the laziest person and they will find the quickest way of doing it.


On Wed, 11 Aug 2004 12:30:56 +0000 (UTC)
Ant <Ant_member@pathlink.com> wrote:

> In article <cfcgjg$4v6$1@digitaldaemon.com>, Arcane Jill says...
> >
> >In article <opscjhxy015a2sq9@digitalmars.com>, Regan Heath says...
> >
> >>Glad to see someone is thinking about how genreally 'nice' this would be without accusing me of being lazy.
> >
> >I take pride in being lazy.
> 
> and of course
> "efficience is the smart lazy"
> (better wording welcome)
> 
> Ant
> 
> 
August 11, 2004
"Jarrett Billingsley" <kb3ctd2@yahoo.com> escribió en el mensaje
news:cf99h1$160a$1@digitaldaemon.com
| or you can do it like this.
|
| enum : ushort
| {
|    THE=0x01;
|    ...
| }
|
| only problem is that you lose the enum name, which is nice to have if you
| have conflicting names (but that shouldn't happen very often).

But then he loses his FooBarBaz type.

-----------------------
Carlos Santander Bernal


August 11, 2004
Regan Heath wrote:
> I have mentioned this before, but I kinda want some more opinions on the matter/idea.
> 
> Currently we have to specify an enum by it's full name, this can be quite long and you can end up writing/copying/pasting the enum name a few times.
> 
> Surely it's possible in most cases for the compiler to determine the Enum name and thus it's not really required.
> 
> Example:
> 
> enum FooBarBaz : ushort
> {
>   THE   = 0x0001,
>   QUICK = 0x0002,
>   BROWN = 0x0004,
>   FOX   = 0x0008,
>   JUMPS = 0x0010,
>   OVER  = 0x0020,
>   THE   = 0x0040,
>   LAZY  = 0x0080,
>   DOG   = 0x0100
> }
> 
> void fooBar(FooBarBaz a) {}
> 
> void main()
> {
>   //current method
>   fooBar(FooBarBaz.THE|FooBarBaz.QUICK|FooBarBaz.BROWN|FooBarBaz.FOX|FooBarBaz.JUMP|FooBarBaz.OVER|FooBarBaz.THE|FooBarBaz.LAZY|FooBarBaz.DOG); 
> 
> 
>   //proposed method
>   fooBar(THE|QUICK|BROWN|FOX|JUMP|OVER|THE|LAZY|DOG);
> 
>   //alternate method
>   fooBar(with(FooBarBaz){THE|QUICK|BROWN|FOX|JUMP|OVER|THE|LAZY|DOG});
> }

I don't think it's a good idea to get DMD guessing which namespaces to search when it can't find a symbol, nor does it feel like a particularly good idea to use the with() construct as an expression.

What would be simpler, and about as useful, though, would be if with() were also usable as an attribute specifier, like public/private/etc.

    class Foo {
        // Java-style
        with(FooBarBaz) const FooBarBaz flags = THE | QUICK | BROWN | FOX;

        // C++-style
    with (FooBarBaz):
        const FooBarBaz flags = ...;
    }

Incidently, it's becoming apparent that we have three different keywords for almost the same thing: with(), import, and alias. :)

 -- andy
August 11, 2004
In article <opscjg92ma5a2sq9@digitalmars.com>, Regan Heath says...
>
>On Tue, 10 Aug 2004 00:28:55 -0500, Deja Augustine <deja@scratch-ware.net> wrote:
>>
>> I can see no justification for coding implicit enum resolution into the compiler when there are several much less ambiguous options available.
>
>Firstly my initial suggestion is not ambiguous, your example, which was not what I was suggesting was ambiguous. To explain, my idea:
>
>enum FooBarBaz {
>   ONE,TWO
>}
>
>fooBar(ONE);
>
>is not any more/less ambiguous than
>
>fooBar(FooBarBaz.ONE);
>
>because if you're wondering what ONE is, and what it means to FooBar you have to lookup both the 'fooBar' function and the 'FooBarBaz' enum. In the case of my example, the former gives you the name of the latter.

But if the 'FooBarBaz' is omitted then the user does not know which enum to check.  This is especially true if fooBar takes an int value and the enum is being implicitly cast.  IMO D corrects what can be a very subtle source of bugs in C/C++ by requiring named enums to be qualified appropriately.  I would very much not like this to change, especially if the reason is just to save a few keystrokes.

>Sure it's not a super important feature/idea, but it's a nice touch, one that so far you have given no real reasons against it, all you have said is:
>  - that I am lazy
>  - that walter has more important thing to do
>  - that it is ambiguous.

The only point I agree with is the one regarding ambiguity.  Consider this code:

# module a;
#
# enum ScreenColor {
#   RED = 1,
#   GREEN = 2,
#   BLUE = 3 }
#
# module b;
#
# enum PaintColor {
#   RED = 53,
#   GREEN = 85,
#   BLUE = 16 }
#
# module c;
#
# void PaintScreen( int color ) { ... }
#
# void main() { PaintScreen( RED ); }

The above is unambiguous because there is only one defined value for RED. However, assume that during the course of maintenance a programmer discovers that he needs something from module b, so he imports that and for some reason removes the line importing module a.  Everything compiles just fine because RED is still defined, but the PaintScreen call is now operating on a completely different value.  In more complex cases such bugs can be extremely difficult to diagnose, especially if the affected code is something that has been left unchanged for years.


Sean


August 11, 2004
On Wed, 11 Aug 2004 21:23:57 +0000 (UTC), Sean Kelly <sean@f4.ca> wrote:
> In article <opscjg92ma5a2sq9@digitalmars.com>, Regan Heath says...
>>
>> On Tue, 10 Aug 2004 00:28:55 -0500, Deja Augustine <deja@scratch-ware.net>
>> wrote:
>>>
>>> I can see no justification for coding implicit enum resolution into the
>>> compiler when there are several much less ambiguous options available.
>>
>> Firstly my initial suggestion is not ambiguous, your example, which was
>> not what I was suggesting was ambiguous. To explain, my idea:
>>
>> enum FooBarBaz {
>>   ONE,TWO
>> }
>>
>> fooBar(ONE);
>>
>> is not any more/less ambiguous than
>>
>> fooBar(FooBarBaz.ONE);
>>
>> because if you're wondering what ONE is, and what it means to FooBar you
>> have to lookup both the 'fooBar' function and the 'FooBarBaz' enum. In the
>> case of my example, the former gives you the name of the latter.
>
> But if the 'FooBarBaz' is omitted then the user does not know which enum to
> check.

Yes they do.. think about how you'd go about it, first you'd look up the function, because what point is knowing the value of the enum if you don't know what's being done with it. The function includes the name of the enum... well... until I read your statement below I assumed it would :)

> This is especially true if fooBar takes an int value and the enum is
> being implicitly cast.

Ahh.. I didn't think of this. :)

So.. 'enum' is implicitly convertable to 'int' but 'int' is not implicitly convertable to 'enum', is that completely sensible do you think?

I guess I assumed as 'int' wasn't implicitly convertable to 'enum' that the reverse would hold true also.


I have just discovered something slightly weird...

enum Test : ubyte {
  ONE = 0x1,
  TWO = 0x2
}

void foo(Test a)
{
}

void main()
{
  foo(Test.ONE);
  foo(Test.ONE|Test.TWO);  //function foo (Test a) does not match argument types (int)
                           //cannot implicitly convert expression cast(int)(1)
                           // | cast(int)(2) of type int to Test
}

Bug? or not?

> IMO D corrects what can be a very subtle source of bugs
> in C/C++ by requiring named enums to be qualified appropriately.  I would very
> much not like this to change, especially if the reason is just to save a few
> keystrokes.

The reason above is the first good one I've heard against my proposal. It probably kills it stone dead too.

>> Sure it's not a super important feature/idea, but it's a nice touch, one
>> that so far you have given no real reasons against it, all you have said
>> is:
>>  - that I am lazy
>>  - that walter has more important thing to do
>>  - that it is ambiguous.
>
> The only point I agree with is the one regarding ambiguity.  Consider this code:
>
> # module a;
> #
> # enum ScreenColor {
> #   RED = 1,
> #   GREEN = 2,
> #   BLUE = 3 }
> #
> # module b;
> #
> # enum PaintColor {
> #   RED = 53,
> #   GREEN = 85,
> #   BLUE = 16 }
> #
> # module c;
> #
> # void PaintScreen( int color ) { ... }
> #
> # void main() { PaintScreen( RED ); }
>
> The above is unambiguous because there is only one defined value for RED.

I assume you're missing an 'import b'; above?

> However, assume that during the course of maintenance a programmer discovers
> that he needs something from module b, so he imports that and for some reason
> removes the line importing module a.  Everything compiles just fine because RED
> is still defined, but the PaintScreen call is now operating on a completely
> different value.  In more complex cases such bugs can be extremely difficult to
> diagnose, especially if the affected code is something that has been left
> unchanged for years.

Yeah.. my assumption about the implicit conversion was the killer.

Regan.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 12, 2004
In article <opscld1nzg5a2sq9@digitalmars.com>, Regan Heath says...

>> This is especially true if fooBar takes an int value and the enum is being implicitly cast.
>
>Ahh.. I didn't think of this. :)

Yes you did. Or at least, your original idea, as I now understand it, completely covers this possibility. It works like this - assume your enum-type-detection system is up and running, then:

#    enum Qwerty { ONE=1, TWO=2 };
#    void f(int x) { /*whatever*/ }
#    f(ONE);

This is simply a compile error, because f takes an int, and therefore "with
Qwerty" is not assumed when parsing f(ONE); Accordingly, ONE is simply an
unknown identifier. To get it to compile, you'd have either to change line 3 to
f(Qwerty.ONE); or else change line 2 to void f(Qwerty x);





>I have just discovered something slightly weird...
>
>enum Test : ubyte {
>   ONE = 0x1,
>   TWO = 0x2
>}
>
>void foo(Test a)
>{
>}
>
>void main()
>{
>   foo(Test.ONE);
>   foo(Test.ONE|Test.TWO);  //function foo (Test a) does not match argument
>types (int)
>                            //cannot implicitly convert expression
>cast(int)(1)
>                            // | cast(int)(2) of type int to Test
>}
>
>Bug? or not?

I think this is what I tried to mention in my last responce. The type of Test.ONE is Test, but the operator | takes ints, and returns an int, so both Test.ONE and Test.TWO are converted to int for the benefit of operator |, and the result is syntactically an int. Since ints cannot be implicitly cast to named enums, you have a compile error. You make it compile by doing:

#   foo(cast(Test)(Test.ONE|Test.TWO));

I have to say, though, I'm not greatly in favor of using enums as bit masks. I realize that (other) people do it all the time, but it seems to me that using an enum variable to hold a numerical value for which there is no corresponding enum name is violating (my conception of) what an enum is for. But that's just me, and I know other people do things differently.


>> IMO D corrects what can be a very subtle source of bugs
>> in C/C++ by requiring named enums to be qualified appropriately.  I
>> would very
>> much not like this to change, especially if the reason is just to save a
>> few
>> keystrokes.
>
>The reason above is the first good one I've heard against my proposal. It probably kills it stone dead too.

I've argued that it doesn't, however, /this/ might do:

#    enum A { ONE=1, TWO=2 };
#    enum B { ONE=2, TWO=1 };
#    void f(A x);
#    void f(B x);
#    f(ONE);

The evaluation of the expression f(ONE) requires an implicit "with", which the compiler can only get from the declaration of f() - but this requires knowing in advance which overload of f() is going to be used. Unfortunately, overload resolution requires knowing the types of the arguments, and so requires the arguments to be parsed /first/. We have ourselves some circularity! The only way out of this would be to allow "implicit withs" only on non-overloaded functions. (Or at least, functions which are not overloaded to the point of ambiguity, but we may be asking too much of the compiler at this point).

Arcane Jill


August 13, 2004
Regan Heath schrieb:

>> Arcane Jill
>> (basically in support but with one or two niggling doubts).
> 
> Glad to see someone is thinking about how genreally 'nice' this would be without accusing me of being lazy.

I would like to silently thumb up the remark and ideas as well.

-eye