December 28, 2007
Janice Caron wrote:
> On 12/28/07, Walter Bright <newshound1@digitalmars.com> wrote:
>> and one is drawn
>> inevitably to conclude that const(T) is always a different type from T.
> 
> I don't think anyone's arguing with that. We're just saying that the
> behavior of auto x = could be tweaked to drop the head constancy.

Yes, but then other things break.


> It's the same with passing things to functions.
> 
>     void f(int x) { /*...*/ }
>     f(DAYS_IN_WEEK);
> 
> we want this to compile, right? Even though DAYS_IN_WEEK is likely to
> have type invariant(uint).

It isn't hard to make invariant(uint) implicitly convertible to uint, so that can work.

> You should always be allowed to create a
> mutable copy (though which preserves tail constancy).

There is no way to do this - unless you can come up with a way to declare tail const member functions in a reasonable way. I failed to solved this problem.
December 28, 2007
Jason House wrote:
> Walter Bright wrote:
>> The idea is that for anonymous enums, there is no type for the
>> enumeration as a whole. Therefore, each member of the enumeration can
>> have a different type.
> 
> ... so annonymous enums have no type for the enumeration as a whole, but
> named enums will?

Yes. That is the way enums already work.


> Can named enums have a type other than int?

Yes. This has always been possible:

enum Foo : long { X, Y }
December 28, 2007
Steven Schveighoffer wrote:
> "Janice Caron" wrote
>> On 12/28/07, Steven Schveighoffer wrote:
>>> ""J�r�me M. Berger""  wrote
>>>> Walter Bright wrote:
>>>>> The reason this won't work is because:
>>>>>     const int x = 3;
>>>>> will type x as const(int), not int. There needs to be a way to declare
>>>>> a
>>>>> constant of type int.
>>>> Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail:
>>>>
>>>> void func (int param)
>>>> {
>>>> }
>>>>
>>>> const int x = 42;
>>>> int y = x;              // <= This should work
>>>> func (x);               // <= This should work too
>>>>
>>>> Or is there something I'm missing here?
>>> I agree with everything you are saying, except I think Walter is thinking
>>> of
>>> the case:
>>>
>>> const int x;
>>> auto y = x;  // y is now const
>> Oooh - I think I ought to say something here, since I was one of the folk arguing that const(T) and const T should be interchangable.
>>
>> The thing is, I just don't see the problem. Given code like:
>>
>>    const int x;
>>    auto y = x;
>>
>> it should be possible to end up with x being a manifest constant, unless the address is taken by some other piece of code somewhere else. As I've mentioned before, x is not merely const, it's actually /invariant/, despite the const declaration, because there is no conceivable way for any piece of code anywhere in the program to change it, ever (...except by doing stuff which is undefined, obviously, but that doesn't count).
>>
>> And that's good, right? If the compiler is really smart, it might be
>> able to treat is as invariant(int). If not, treating it as const(int)
>> is harmless.
>>
>> But as for y...
>>
>> y is a /copy/ of x, and clearly it should be possible to make a copy
>> of a const thing and have the copy be mutable. Head constness needs to
>> be dropped here, exactly as it is dropped in template distinction in
>> D2.008 (t!(int) is the same thing as t!(const(int)) unless special
>> syntax is used).
>>
>> In fact, x is very much like a template, and could be implemented in a
>> similar way - don't instantiate it (allocate it storage space in the
>> ROM segment) unless it is referenced (its address is taken).
>>
>> I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.
>>
> 
> I don't disagree with you :)  I'm merely clarifying Walter's gripe.
> 
> I think there may be a better reason why your idea wouldn't work, but I am not sure how the compiler is implemented, so I can't really say much. However, it might be a problem when you are defining constants in one module to be used in other modules.  How does the compiler know that those constants won't have their address taken somewhere else?  When the compiler creates the object file, it has to assume since the symbol is public, it can have its address taken, no?
> 
> If you had a specific D linker,  you could modify the linker to take this into account, but that is not the case today.
> 
	You do it the same way it is done for templates (and in particular
for the associated type information data): you allocate it in each
module that uses it, but you put it in a special section that tells
the linker to merge duplicate definitions.

		Jerome
- --
+------------------------- Jerome M. BERGER ---------------------+
|    mailto:jeberger@free.fr      | ICQ:    238062172            |
|    http://jeberger.free.fr/     | Jabber: jeberger@jabber.fr   |
+---------------------------------+------------------------------+
December 28, 2007
Steven Schveighoffer wrote:
> That brings up a couple of questions.  Under the new regime, what happens with this code:
> 
> enum {one, two}

No change here, one and two are ints with values 0 and 1.

> enum : long {one, two}

No change here, one and two are longs with values 0 and 1.

> enum : float {one, two}

Change here, floats are now allowed as the base type, one and two are floats with values 0.0f and 1.0f.

> enum
> {
>   float one = 1.0,
>   two
> }

Change here, one is float of value 1.0f, two is float of value 2.0f.

> and will enums in curly braces that are manifest constants have to be specified with semicolons or commas?

commas.
December 28, 2007
Janice Caron wrote:
> On 12/28/07, Walter Bright <newshound1@digitalmars.com> wrote:
>> Janice Caron wrote:
>>> y is a /copy/ of x, and clearly it should be possible to make a copy
>>> of a const thing and have the copy be mutable.
>> That doesn't work for structs or classes.
> 
> It doesn't? For structs
> 
>     struct S {}
>     const S x;
>     auto y = x;

Imagine you have:
	struct S { int* p; }
Because const is transitive, const(S) implies that now p points to const. But if you strip off the const in the assignment, you've lost the const-ness of p, and now you have a gaping hole in the const-correctness.

> Isn't
> 
>     class C {}
>     enum { C x; }
>     auto y = x;
> 
> exactly the same problem?

No, because y will be of type C and will have the value null.

>> Just for fun, how would we define a tail const member function?
> 
> Yeah, I agreed, it wouldn't work for classes. Still don't see any
> problem for structs though.

You'd need tail const member functions for structs, too.
December 28, 2007
Jérôme M. Berger wrote:
> 	I agree that "const (int)" and "int" should be different types.
> What I don't really see is why manifest constant need to be "int"
> rather than "const (int)". After all, any attempt to use one as
> non-const will fail (or should) so there's no real reason that they
> can't be "const (int)", is there?

Since one cannot take the address of a manifest constant, the requirement that it be immutable goes away, since it can never be an lvalue.
December 28, 2007
Walter Bright wrote:
> Steven Schveighoffer wrote:
>> This is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included).  There are much better ways to solve this problem than destroying the traditional meaning of enum.
> 
> I understand your point, but also consider that adding yet a fourth way to declare constants is not going to be illuminating for newcomers, and it makes D look like a mishmash.
> 
	Except that you're already "adding a fourth way to declare
constants" so it is already "not illuminating for newcomers" and it
already "makes D look like a mishmash". But using "enum" only
aggravates the situation: newcomers will face something that they
think they know ("enum") but actually don't really.

> Furthermore, it does not destroy the meaning of enum. Already, you can do this in C, C++ and D:
> 
>   enum { x = 1, y = 2 }   // x and y are int's
> 
	There is an additional implied meaning here: x and y are related:
they are either alternate choices for some value or flags that may
be or'ed together. No compiler enforces that, but I've never seen it
used to declare wildly unrelated values (and I would consider it a
poor coding practice).

		Jerome
- --
+------------------------- Jerome M. BERGER ---------------------+
|    mailto:jeberger@free.fr      | ICQ:    238062172            |
|    http://jeberger.free.fr/     | Jabber: jeberger@jabber.fr   |
+---------------------------------+------------------------------+
December 28, 2007
Walter Bright wrote:
> Jérôme M. Berger wrote:
>>     I agree that "const (int)" and "int" should be different types.
>> What I don't really see is why manifest constant need to be "int"
>> rather than "const (int)". After all, any attempt to use one as
>> non-const will fail (or should) so there's no real reason that they
>> can't be "const (int)", is there?
> 
> Since one cannot take the address of a manifest constant, the requirement that it be immutable goes away, since it can never be an lvalue.

	Right. Replace "const" by "invariant" in my comment and the main
point still stands: couldn't the compiler determine automatically if
we take the address of an invariant variable and allocate memory for
it or not based on that? This would remove the need for a special
keyword/syntax for manifest constants: just declare them as
"invariant" and let the compiler do the work.

		Jerome
- --
+------------------------- Jerome M. BERGER ---------------------+
|    mailto:jeberger@free.fr      | ICQ:    238062172            |
|    http://jeberger.free.fr/     | Jabber: jeberger@jabber.fr   |
+---------------------------------+------------------------------+
December 28, 2007
On Fri, 28 Dec 2007 18:43:38 -0000, Walter Bright <newshound1@digitalmars.com> wrote:

> Sean Kelly wrote:
>> err... make that unnamed and named.  One could argue that support for unnamed enums is simply for ease of porting from C rather than because it's a feature that really makes sense in a new language.  So making it even more entrenched is undesirable.  But we need the feature and if "enum" is it then...
>
> Right. Anonymous enums are already conventionally used not to declare enums, but a bunch of (not necessarily related) manifest constants. In fact, in C++ we see:
>
> template<> class factorial<1>
> {
>    public:
>      enum { result = 1 };
> };
>
> where anonymous enums are clearly used to declare manifest constants.

That looks similar to the workaround for old compilers which didn't support static consts.

template<> class factorial<1>
{
   public:
     static const int result = 1;
};

I can see the desire for manifest constants here. You particularly don't want to bloat your code
with each intermediate value in a compile time computed expression.
I've just tried an experiment on gcc (cygming 3.4.4). Compiled objects are the same size whether
enum or static const is used in a factorial template. I see this as evidence that the enum hack
is still just that, a hack to workaround dodgey compilers. So you are propagating a hack into D
if the C++ example is one of your primary reasons.
December 28, 2007
Jason House wrote:
> ... so annonymous enums have no type for the enumeration as a whole, but named enums will?  Can named enums have a type other than int?

I really meant other than integral types.  More accurately, however, I should have asked if named enums can contain as diverse a set of types as unnamed enums.

I'm not sure what can be a manifest constant...  int, long, float, string, struct, etc...