www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - auto storage class - infer or RAII?

reply Walter Bright <newshound digitalmars.com> writes:
The auto storage class currently is a little fuzzy in meaning, it can 
mean "infer the type" and/or "destruct at end of scope". The latter only 
has meaning for class objects, so let's look at the syntax. There are 4 
cases:

class Class { }

1) auto c = new Class();
2) auto Class c = new Class();
3) auto c = some_expression();
4) auto Class c = some_expression();

The ambiguity can be resolved by saying that if auto is used for type 
inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
not used for type inference, i.e. cases (2) and (4), then it does mean RAII.

In the future, I'd like the following to work:

5) auto c = Class();

which would mean type inference *and* RAII.
Nov 11 2006
next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Walter Bright escribió:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Since this has been talked a lot already, I'll only say: auto for RAII, and something else (eg: var) for type inference. IMHO. -- Carlos Santander Bernal
Nov 11 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Carlos Santander wrote:
 Walter Bright escribió:
 
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter 
 only has meaning for class objects, so let's look at the syntax. There 
 are 4 cases:

and something else (eg: var) for type inference. IMHO.

I agree. Even if "everybody else is doing it", I think auto is a poor choice for an automatic type deduction indicator. I'd be much happier with any of var foo = expression; val foo = expression; def foo = expression; let foo = expression; As an added bonus all of those are one character less than the current auto. Which is good, since automatic type deduction is basically a typing saving feature to begin with. To me 'auto' in front of an identifier looks like it's saying this is an "automatic variable", which, going back to the original K&R book, has always meant a local, scoped variable. It sounds like it's going to do something at run time. For anyone who complains "I'm using that as a variable name already", I'll write you a script to fix your files. Here you go perl -pi -e 's/(\W)(val)(\W)/${1}${2}_${3}/g' *.d Or if you may already have things name val_ in your code perl -pi -e 's/(\W)(val_*)(\W)/${1}${2}_${3}/g' *.d --bb
Nov 11 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Bill Baxter wrote:
 Which is good, since automatic type deduction is basically a 
 typing saving feature to begin with.

No, it's way way more than that. Auto type deduction gets us much closer to the goal of the type of something only needs to be specified once, and then anything that manipulates it infers the right type. This makes code much more robust. For example, auto len = foo.length; What is the type of foo.length? Is it an int? uint? size_t? class Abc? Without type inference, I'd have to go look it up. With type inference, I know I've got the *correct* type for i automatically. Now, suppose I change the type of foo.length. I've got to go through and check *every* use of it to get the types of the i's updated. I'll inevitably miss one and thereby have a bug. With automatic type inference, I'm done before I start, and it's done correctly. The fewer types one has to specify, the better, and note that none of the advantages of static typechecking are lost, either.
Nov 12 2006
next sibling parent reply "Jim Hewes" <jhewesNOSPAM ix.netcom.com> writes:
I hope you don't mind a comment from a lurker. :)

I had assumed that there was some more important purpose for type inference, 
such as that it was useful in generics or something. But if it's just to 
avoid having to declare types, I wonder if it's really that important to 
have.

"Walter Bright" <newshound digitalmars.com> wrote in message 
news:ej6vb3$2s5m$1 digitaldaemon.com...
 What is the type of foo.length? Is it an int? uint? size_t? class Abc? 
 Without type inference, I'd have to go look it up. With type inference, I 
 know I've got the *correct* type for i automatically.

However, you don't know what that type is. If you want to know, you need to go look it up. This is especially true if you're working on someone else's code. I think that's fine if you're working within an IDE that can tell you the type. I'm not a fan of Hungarian notation. When working within Visual Studio for example, there are multiple ways to find the type of a variable easily. You can hover the mouse over it. You can right-click on it and select "Go to Declaration". I think this obviates things like Hungarian notation. It would help with discovering the types of inferred variables. But if you're using some editor like vi, then you may find it tedious and time-consuming to always search for the types of variables. I would be more likely to avoid type inference altogether and simply write the type just for the sake of documenting it.
 Now, suppose I change the type of foo.length. I've got to go through and 
 check *every* use of it to get the types of the i's updated. I'll 
 inevitably miss one and thereby have a bug.

I assume if you've made an assignment to the wrong variable type, the compiler will catch this (unless there's an implicit cast). At least the compiler errors should help you find all occurrences easily. Although, you'd still need to go through and manually change the type in each occurrence. I just feel that making these kinds of changes to code are more the job of development tools. Perhaps the line between language and tools can start to get a little blurry; that's another discussion. Anyway, I just wonder if there is a strong a case for having type inference at all. Jim
Nov 12 2006
parent Walter Bright <newshound digitalmars.com> writes:
Jim Hewes wrote:
 I hope you don't mind a comment from a lurker. :)

Not at all.
 I had assumed that there was some more important purpose for type inference, 
 such as that it was useful in generics or something. But if it's just to 
 avoid having to declare types, I wonder if it's really that important to 
 have.

I think I must have presented the case for it very poorly. The goal is to minimize bugs; avoiding having to declare types is a means to that goal, not the end itself.
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ej6vb3$2s5m$1 digitaldaemon.com...
 What is the type of foo.length? Is it an int? uint? size_t? class Abc? 
 Without type inference, I'd have to go look it up. With type inference, I 
 know I've got the *correct* type for i automatically.

However, you don't know what that type is. If you want to know, you need to go look it up. This is especially true if you're working on someone else's code. I think that's fine if you're working within an IDE that can tell you the type. I'm not a fan of Hungarian notation. When working within Visual Studio for example, there are multiple ways to find the type of a variable easily. You can hover the mouse over it. You can right-click on it and select "Go to Declaration". I think this obviates things like Hungarian notation. It would help with discovering the types of inferred variables.

If you're always viewing code by using such a tool, then discovering the type is trivial as you suggest. But even with such a tool available, lots of times you won't be using it to view the code. And just to make it clear, I am not advocating Hungarian notation in the sense that it normally means (I do think, however, such notation used in the manner that Joel Spolsky writes about is useful). http://www.joelonsoftware.com/articles/Wrong.html
 But if you're using some editor like vi, then you may find it tedious and 
 time-consuming to always search for the types of variables. I would be more 
 likely to avoid type inference altogether and simply write the type just for 
 the sake of documenting it.

I'd posit here that if type inference is possible, then perhaps documenting the type at that point is the wrong place to document it.
 Now, suppose I change the type of foo.length. I've got to go through and 
 check *every* use of it to get the types of the i's updated. I'll 
 inevitably miss one and thereby have a bug.

I assume if you've made an assignment to the wrong variable type, the compiler will catch this (unless there's an implicit cast).

That's just the problem. There is a lot of implicit casting going on. Consider .length - it often does mean int, uint, size_t, etc., and there are implicit casts between them. So if you 'document' it as int, then there's a bug if it really should be size_t.
 At least the 
 compiler errors should help you find all occurrences easily.

Unfortunately, it doesn't. One could counter with "make all implicit casting illegal." Pascal tried that, and in my not-so-humble-opinion that was a big reason for the failure of Pascal, and it's the primary reason why I dropped it as soon as I discovered C. Even so, who wants to go through their source, compiler error by compiler error, fixing it? If the work could be cut in half using type inference, why not?
 Although, you'd 
 still need to go through and manually change the type in each occurrence. I 
 just feel that making these kinds of changes to code are more the job of 
 development tools. Perhaps the line between language and tools can start to 
 get a little blurry; that's another discussion. Anyway, I just wonder if 
 there is a strong a case for having type inference at all.

It is optional. The ability to explicitly type declarations is not going to go away.
Nov 12 2006
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 
 Which is good, since automatic type deduction is basically a typing 
 saving feature to begin with.

No, it's way way more than that. Auto type deduction gets us much closer to the goal of the type of something only needs to be specified once, and then anything that manipulates it infers the right type. This makes code much more robust. For example, auto len = foo.length; What is the type of foo.length? Is it an int? uint? size_t? class Abc? Without type inference, I'd have to go look it up. With type inference, I know I've got the *correct* type for i automatically.

From a software maintenance and robustness standpoint I think that cuts both ways. If I don't know the type then it's easy to do something wrong with it like auto len = foo.length; len = -1; // oops! len is unsigned! not what I intended! From the point of view of someone reading and maintaining code, I hope the only places I see auto are where the type is obvious from the context, like auto foo = new SomeClassWithALongNameIDontWantToTypeTwice. I think it's bad practice to use auto just becuase you're too lazy to go figure out what the right type is. If you don't figure it out when writing it, then every person after you reading or maintaining the code is going to have to go figure it out. --bb
Nov 12 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Bill Baxter wrote:
  From a software maintenance and robustness standpoint I think that cuts 
 both ways.  If I don't know the type then it's easy to do something 
 wrong with it like
 
    auto len = foo.length;
    len = -1;  // oops! len is unsigned!  not what I intended!

If you wrote: int len = foo.length; and foo.length was unsigned, isn't that just another sort of bug?
  From the point of view of someone reading and maintaining code, I hope 
 the only places I see auto are where the type is obvious from the 
 context, like auto foo = new SomeClassWithALongNameIDontWantToTypeTwice.

I see it as much more useful than that.
 I think it's bad practice to use auto just becuase you're too lazy to go 
 figure out what the right type is.  If you don't figure it out when 
 writing it, then every person after you reading or maintaining the code 
 is going to have to go figure it out.

Not necessarily. Think of it like writing templates that depend on a generic type T and assume certain properties of that type.
Nov 12 2006
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
  From a software maintenance and robustness standpoint I think that 
 cuts both ways.  If I don't know the type then it's easy to do 
 something wrong with it like

    auto len = foo.length;
    len = -1;  // oops! len is unsigned!  not what I intended!

If you wrote: int len = foo.length; and foo.length was unsigned, isn't that just another sort of bug?

Yeh, I suppose. On the other hand my specification of a type is a kind of contract that the compiler can check. Both have their uses, but I'm just saying specifying the type should be the default policy, unless there's a compelling reason not to (i.e. it's obvious from context). I guess the best maintenance argument for why auto should be used sparingly is that information should be as localized as possible. It's why C++ gurus say you should declare at point of use whenever possible (rather than using C-style top-of-the-function declarations). It's also one reason why globals are considered bad, and why creative operator overloading is a bad idea. All those things can make you have to go searching all over your codebase to figure out the meaning of one little line of code. --bb
Nov 12 2006
prev sibling next sibling parent reply "Chris Miller" <chris dprogramming.com> writes:
On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright  =

<newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it can =

 mean "infer the type" and/or "destruct at end of scope". The latter on=

 has meaning for class objects, so let's look at the syntax. There are =

 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" = = for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for au= to = destruction, which frees up "auto" for auto type deduction: scope Object o =3D new Object(); // Destructed at end of scope. scope auto q =3D new Foo(); // Auto type deduction and end-of-scope = = destruction.
Nov 11 2006
next sibling parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
Chris Miller wrote:

 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright
 <newshound digitalmars.com> wrote:
 
 The auto storage class currently is a little fuzzy in meaning, it can
 mean "infer the type" and/or "destruct at end of scope". The latter only
 has meaning for class objects, so let's look at the syntax. There are 4
 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

Considering that scope already exists as a keyword, I find this an excellent suggestion that is also very much clearer in meaning (I find auto to miss the target for both cases really :P ). -- Lars Ivar Igesund blog at http://larsivi.net DSource & #D: larsivi
Nov 11 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Lars Ivar Igesund wrote:
 Chris Miller wrote:
 
 
On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright
<newshound digitalmars.com> wrote:


The auto storage class currently is a little fuzzy in meaning, it can
mean "infer the type" and/or "destruct at end of scope". The latter only
has meaning for class objects, so let's look at the syntax. There are 4
cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

Considering that scope already exists as a keyword, I find this an excellent suggestion that is also very much clearer in meaning (I find auto to miss the target for both cases really :P ).

I've already said it before, but it bears repeating yet again. I also prefer 'scope' for this. Although 'infer' wouldn't be bad -- but please, please, please, not 'var'! It smells too much like a scripting language construct, and besides, my Bovis code is overflowing with actual variables named var. (Probably because of the BVar struct that it passes most values around as. Go figure.) -- Chris Nicholson-Sauls
Nov 11 2006
parent reply Tydr Schnubbis <fake address.dude> writes:
Chris Nicholson-Sauls wrote:
 Considering that scope already exists as a keyword, I find this an excellent
 suggestion that is also very much clearer in meaning (I find auto to miss
 the target for both cases really :P ).
 

I've already said it before, but it bears repeating yet again. I also prefer 'scope' for this. Although 'infer' wouldn't be bad -- but please, please, please, not 'var'! It smells too much like a scripting language construct, and besides, my Bovis code is overflowing with actual variables named var. (Probably because of the BVar struct that it passes most values around as. Go figure.)

'scope' and 'infer' sound good to me, very to-the-point and unambiguous. No need to make people wonder if 'auto' works like in C or not, etc. Just drop it.
Nov 11 2006
next sibling parent Tydr Schnubbis <fake address.dude> writes:
Tydr Schnubbis wrote:
 Chris Nicholson-Sauls wrote:
 Considering that scope already exists as a keyword, I find this an excellent
 suggestion that is also very much clearer in meaning (I find auto to miss
 the target for both cases really :P ).
 

I've already said it before, but it bears repeating yet again. I also prefer 'scope' for this. Although 'infer' wouldn't be bad -- but please, please, please, not 'var'! It smells too much like a scripting language construct, and besides, my Bovis code is overflowing with actual variables named var. (Probably because of the BVar struct that it passes most values around as. Go figure.)

'scope' and 'infer' sound good to me, very to-the-point and unambiguous. No need to make people wonder if 'auto' works like in C or not, etc. Just drop it.

It just occurred to me that since it's not the keyword itself that makes type inference happen, but the lack of a type specifier, maybe 'var' is better than 'infer' after all. I mean, since it doesn't really do anything, per se.
Nov 11 2006
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Tydr Schnubbis wrote:
 Chris Nicholson-Sauls wrote:
 
 Considering that scope already exists as a keyword, I find this an 
 excellent
 suggestion that is also very much clearer in meaning (I find auto to 
 miss
 the target for both cases really :P ).

I've already said it before, but it bears repeating yet again. I also prefer 'scope' for this. Although 'infer' wouldn't be bad -- but please, please, please, not 'var'! It smells too much like a scripting language construct, and besides, my Bovis code is overflowing with actual variables named var. (Probably because of the BVar struct that it passes most values around as. Go figure.)

'scope' and 'infer' sound good to me, very to-the-point and unambiguous. No need to make people wonder if 'auto' works like in C or not, etc. Just drop it.

"scope" seems a pretty popular suggestion. I find it not so bad myself, but I would prefer "scoped" because it's less ambiguious. "scope" makes sense if you think of scope as a verb (scope this variable), but just seeing it outside of a sentence it looks like a noun (this variable is a scope -- huh?), simply because 'scope' isn't used as a verb very often in English. 'scoped' is clearly an adjective, as in 'this variable is scoped'. And being an adjective puts it in good company with most of the other storage classes which are also adjectives: (abstract, auto(matic), const(ant), deprecated, extern(al), final, static, synchronized). The only non-adjective storage class is 'override'. I have no idea why it's not "overridden". It should be. At least override reads clearly, whether you take it to be a noun (this is an override) or a verb (override the method). "Scope" does not have this property. "This is a scope" does not make sense. --bb
Nov 11 2006
parent reply "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
Bill Baxter wrote:

 "scope" seems a pretty popular suggestion.
 I find it not so bad myself, but I would prefer "scoped" because it's less
 ambiguious.  "scope" makes sense if you think of scope as a verb (scope this
 variable), but just seeing it outside of a sentence it looks like a noun
 (this variable is a scope -- huh?), simply because 'scope' isn't used as a
 verb very often in English.
 
 'scoped' is clearly an adjective, as in 'this variable is scoped'. 

Yes I also thought of 'scoped'. Sounds like a good idea to me. But I can live with 'scope' or 'var' as well. I don't like the original proposal 'auto x = ClassName(...)' // type inference, new object, RAII because sometimes it is hard to distinguish between ClassName (i.e. new object is created) and FunctionName (it's returned) With 'scoped' it's clear: 1) auto a = new A(); // type inference, new object, no RAII 2) scoped a = new A(); // type inference, new object, RAII 3) auto a = SomeFunc(); // type inference, object returned from func, no RAII 4) scoped a = SomeFunc(); // type inference, object returned from func, RAII and of course longer form should be also possible: 'scoped A a = new A();' // RAII, no type inference
 And being
 an adjective puts it in good company with most of the other storage classes
 which are also adjectives: (abstract, auto(matic), const(ant), deprecated,
 extern(al), final, static, synchronized).  
 The only non-adjective storage
 class is 'override'.  I have no idea why it's not "overridden".

I think because 'overridden' is too long to type. I also think "lock(x)" could be better than "synchronized(x)" for the same reason. -- AKhropov
Nov 12 2006
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Andrey Khropov wrote:
 Bill Baxter wrote:
 
 "scope" seems a pretty popular suggestion.
 I find it not so bad myself, but I would prefer "scoped" because it's less
 ambiguious.  "scope" makes sense if you think of scope as a verb (scope this
 variable), but just seeing it outside of a sentence it looks like a noun
 (this variable is a scope -- huh?), simply because 'scope' isn't used as a
 verb very often in English.

 'scoped' is clearly an adjective, as in 'this variable is scoped'. 

Yes I also thought of 'scoped'. Sounds like a good idea to me.

I realized 'scope' is already a keyword. I think that's why people are gravitating towards that instead of the more natural 'scoped'. I think the globally optimum solution would be to make the other 'scope' into 'scoped' too. scoped(exit) writefln("leaving now"); That reads just fine to me. Whereas scope var = new Class; looks funny. Oh well. Probably hopeless. --bb
Nov 12 2006
prev sibling next sibling parent Boris Kolar <boris.kolar globera.com> writes:
== Quote from Chris Miller (chris dprogramming.com)'s article
     scope Object o =3D new Object(); // Destructed at end of scope.

Excellent suggestion! I would also like to see scoped classes like: scope class AutoDestroy { } AutoDestroy createAutoDestroyObject() { return new AutoDestroy(); } void test() { AutoDestroy d = createAutoDestroyObject(); // d will be destroyed here } This way, I can use classes with deterministic destruction the same way as other classes. Scoped classes should also be able to be returned from functions, passed as parameters, or be fields of other scoped classes. It is up to programmer (and maybe, later, compiler escape analysis) to make sure variable doesn't escape scope. This is the #1 feature on my wish list and I really, really need it. Absence of good RAII is a major pain (auto classes are way too restricted).
Nov 11 2006
prev sibling next sibling parent reply Kyle Furlong <kylefurlong gmail.com> writes:
Chris Miller wrote:
 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright 
 <newshound digitalmars.com> wrote:
 
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter 
 only has meaning for class objects, so let's look at the syntax. There 
 are 4 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

scope has my vote, its elegant, as raii is functionally similar to the scope(x) construct.
Nov 11 2006
parent reply Dave <Dave_member pathlink.com> writes:
Kyle Furlong wrote:
 Chris Miller wrote:
 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright 
 <newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter 
 only has meaning for class objects, so let's look at the syntax. 
 There are 4 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

scope has my vote, its elegant, as raii is functionally similar to the scope(x) construct.

Vote++. But Walter specifically (and I think purposefully) left out any mention of new keywords. Nonetheless I'd like to see auto deprecated in favor of 'infer'. 'scope' and 'infer' both describe exactly what they are used for. 'auto' just seems too much like a deprecated artifact of C. Based on previous discussions though, 'auto' is here to stay one way or the other forever. I sincerely don't understand Walter's infatuation with 'auto', but it is what it is.
Nov 11 2006
parent reply Don Clugston <dac nospam.com.au> writes:
Dave wrote:
 Kyle Furlong wrote:
 Chris Miller wrote:
 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright 
 <newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it 
 can mean "infer the type" and/or "destruct at end of scope". The 
 latter only has meaning for class objects, so let's look at the 
 syntax. There are 4 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

scope has my vote, its elegant, as raii is functionally similar to the scope(x) construct.

Vote++. But Walter specifically (and I think purposefully) left out any mention of new keywords. Nonetheless I'd like to see auto deprecated in favor of 'infer'. 'scope' and 'infer' both describe exactly what they are used for.

type that means type inference. But the usage of auto to mean both 'raii' and 'local variable storage class' is really confusing people.
 'auto' just seems too much like a deprecated artifact of C.

Agreed, but I don't know of anything better. const infer x = 3.5; static infer x = 4.5L; are too wordy.
 Based on previous discussions though, 'auto' is here to stay one way or 
 the other forever. I sincerely don't understand Walter's infatuation 
 with 'auto', but it is what it is.

Nov 12 2006
parent Dave <Dave_member pathlink.com> writes:
Don Clugston wrote:
 Dave wrote:
 Kyle Furlong wrote:
 Chris Miller wrote:
 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright 
 <newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it 
 can mean "infer the type" and/or "destruct at end of scope". The 
 latter only has meaning for class objects, so let's look at the 
 syntax. There are 4 cases:

Choosing from your list I guess "auto" for auto destruction and "infer" for auto type deduction. However, I tend to prefer "scope" (without parentheses following) for auto destruction, which frees up "auto" for auto type deduction: scope Object o = new Object(); // Destructed at end of scope. scope auto q = new Foo(); // Auto type deduction and end-of-scope destruction.

scope has my vote, its elegant, as raii is functionally similar to the scope(x) construct.

Vote++. But Walter specifically (and I think purposefully) left out any mention of new keywords. Nonetheless I'd like to see auto deprecated in favor of 'infer'. 'scope' and 'infer' both describe exactly what they are used for.

type that means type inference. But the usage of auto to mean both 'raii' and 'local variable storage class' is really confusing people.

I realize 'auto' is technically the default storage class, but was suggesting when both a storage class and type are absent, 'infer' would be used (and not as a storage class) instead of auto.
 'auto' just seems too much like a deprecated artifact of C.

Agreed, but I don't know of anything better. const infer x = 3.5; static infer x = 4.5L; are too wordy.

I think so too, but I don't think 'infer' would be necessary in those cases, even for the sake of consistency.
 Based on previous discussions though, 'auto' is here to stay one way 
 or the other forever. I sincerely don't understand Walter's 
 infatuation with 'auto', but it is what it is.


Nov 12 2006
prev sibling parent "Chris Miller" <chris dprogramming.com> writes:
On Sat, 11 Nov 2006 14:22:19 -0500, Chris Miller <chris dprogramming.com=
  =

wrote:
 On Sat, 11 Nov 2006 13:48:00 -0500, Walter Bright  =

 <newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it can=


 mean "infer the type" and/or "destruct at end of scope". The latter  =


 only has meaning for class objects, so let's look at the syntax. Ther=


 are 4 cases:

Choosing from your list I guess "auto" for auto destruction and "infer=

 for auto type deduction.

 However, I tend to prefer "scope" (without parentheses following) for =

 auto destruction, which frees up "auto" for auto type deduction:

     scope Object o =3D new Object(); // Destructed at end of scope.
     scope auto q =3D new Foo(); // Auto type deduction and end-of-scop=

 destruction.

Actually, could probably also reuse "typeof" for auto type deduction: typeof x =3D new X;
Nov 11 2006
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 11 Nov 2006 10:48:00 -0800, Walter Bright wrote:

 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Please excuse my bash and amateur crashing in here ... but Walter, for a very intelligent person, why is it that you just don't get it? Type inference and RAII are two distinct, unrelated and orthogonal concepts. Using one keyword in subtly different syntax permutations to indicate both concepts is just plain stupid. In each of the suggested permutations above, the code reader and writer will constantly be thinking "now what's the precise syntax again?" This reminds me of the exact criticism that you have leveled against some C++ constructs, and some syntax changes to D suggested by your supporters. Namely that the subtle differences in syntax variants is a cause of bugs and makes writing code harder - because they are not visually distinct enough for the average person. Why do we want Type Inference? At least two reason pop into mind; to help write generic code, which means less rewriting/editing of code, and to avoid using long type names (shorter words to type). Thus a short keyword to indicate type inference would be a better idea than using a long word. Why do we want RAII? So we don't have to also write explicit 'destructor' invocation code and thus reduce the amount of coding required. So again, a short keyword rather than a long keyword would be more beneficial. However, to use the same keyword for these two unrelated uses is an ugly wart on your language. Further more 'auto' is ambiguous? Is it 'automatic'-inference, 'automatic'-RAII, 'automatic'-<some_thing_else>? My plea is ... (a) Get rid of 'auto'. (b) Create a new keyword that is more obviously read as 'type inference'. (c) Create a new keyword that is more obviously read as 'resource destruction at end of scope'. (d) Allow any combination of these new keywords on the same declaration statement. (e) Allow any combination of these new keywords on declarations at the module level. That will make reading and writing D code less costly, and increase the joy in using your wonderful language. -- Derek Parnell
Nov 11 2006
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Sun, 12 Nov 2006 10:44:37 +1100, Derek Parnell wrote:

 On Sat, 11 Nov 2006 10:48:00 -0800, Walter Bright wrote:
 
 The auto storage class currently is a little fuzzy in meaning


By the way, I refuse to use the current 'auto' nowadays precicely because it adds to the cost of code maintenance, due to its ability to confuse and/or mislead code readers. -- Derek Parnell
Nov 11 2006
next sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Derek Parnell wrote:
 On Sun, 12 Nov 2006 10:44:37 +1100, Derek Parnell wrote:
 
 On Sat, 11 Nov 2006 10:48:00 -0800, Walter Bright wrote:

 The auto storage class currently is a little fuzzy in meaning


By the way, I refuse to use the current 'auto' nowadays precicely because it adds to the cost of code maintenance, due to its ability to confuse and/or mislead code readers.

I do use auto, but only because I never use RAII, so there's no room for confusion (for me) when I read my code.
Nov 11 2006
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Derek Parnell wrote:
 On Sun, 12 Nov 2006 10:44:37 +1100, Derek Parnell wrote:
 
 
On Sat, 11 Nov 2006 10:48:00 -0800, Walter Bright wrote:


The auto storage class currently is a little fuzzy in meaning
class Class { }

1) auto c = new Class();
2) auto Class c = new Class();
3) auto c = some_expression();
4) auto Class c = some_expression(); 



5) auto c = Class(); 



At least the first 4 have some consistent logic behind them, but #5 is just pure special casing for something that's not all that common or special. It should just be auto auto c = new Class(); Besides Class may have a static opCall, no? Anyway, to me, all these things look harder to disinguish than even the a..b vs a...b thing, which you didn't like, so I'm baffled as to why you are so resistant to make 'auto' usages easier to distinguish.
 By the way, I refuse to use the current 'auto' nowadays precicely because
 it adds to the cost of code maintenance, due to its ability to confuse
 and/or mislead code readers.

Agreed. I stick with auto for auto-type inference, but I don't go near the other usage because it's just too confusing to have two different kinds of auto's in my code that can appear in such similar syntactic situations. I have my preferences as already stated, but I would be satisfied, if not overjoyed, with any solution that A) makes the keywords for RAII and ATI distinct, and B) doesn't make the ATI keyword any longer than it already is. Part of why I want auto for ATI to be short is that will get a lot of use. There are already 50 or so uses of auto in phobos/std/*.d. It looks like maybe 2 are RAII things but the rest are all ATI. So ATI is more common than RAII. Maybe ATI is common enough that it even warrants special syntax? If so then I think the at-sign makes sense for that. "AuTo"->"at" -- close enough for a mnemonic. That would mean "auto foo" could be compressed to " foo". Some examples of what it would look like: foo = some_expression(); bar = other_thing(); for ( v = start; v<end; v++) {...} if ( m = std.regexp.search("abcdef", "c()")) dim = this.dim(); sort(list, ( a, b){ return a.val-b.val; } // though I think in this case it should be allowable to omit the // auto's/ 's and just have sort(list, (a,b){...}); --bb
Nov 11 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Bill Baxter wrote:
 Derek Parnell wrote:
 
 So ATI is more common than RAII.  Maybe ATI is common enough that it 
 even warrants special syntax?  If so then I think the at-sign makes 
 sense for that. "AuTo"->"at" -- close enough for a mnemonic.  That would 
 mean "auto foo" could be compressed to " foo".
 
 Some examples of what it would look like:
 
      foo = some_expression();
     bar = other_thing();
 
    for ( v = start; v<end; v++) {...}
 
    if ( m = std.regexp.search("abcdef", "c()"))
 
     dim = this.dim();
 
    sort(list,  ( a, b){ return a.val-b.val; }
      // though I think in this case it should be allowable to omit the
      // auto's/ 's and just have sort(list, (a,b){...});

Addendum: I personally find the implicit 'auto' in foreach to be a little jarring. Every time I see foreach(e; elements) {} I find myself looking around for where e is declared. Especially since foreach looks so much like a variation on a for loop, but 'auto' isn't automatic in a for loop in D (though after I learned about foreach, I assumed incorrectly it would work in D's for-loop too.). Additionally I keep getting bitten by things like int i; for (i=1; i<10; i++) { } ... foreach(i,elem; elements) { if (...) break; } writefln("last i was", i) Which using 'foreach-is-like-for' mentality seems perfectly natural but causes the compiler to complain. Anyway, e might be short enough that there wouldn't be any need to special case the foreach. Just use foreach( i, e; elements) { ... } --bb
Nov 11 2006
parent Walter Bright <newshound digitalmars.com> writes:
Bill Baxter wrote:
 Additionally I keep getting bitten by things like
     int i;
     for (i=1; i<10; i++) {
     }
     ...
     foreach(i,elem; elements) {
        if (...) break;
     }
     writefln("last i was", i)
 
 Which using 'foreach-is-like-for' mentality seems perfectly natural but 
 causes the compiler to complain.

I know it's a little different, but it's so convenient. Also, the no-shadowing rule helps flush out errors at compile time before one gets bitten.
Nov 12 2006
prev sibling next sibling parent reply "Lionello Lunesu" <lionello lunesu.remove.com> writes:
 Please excuse my bash and amateur crashing in here ... but Walter, for a
 very intelligent person, why is it that you just don't get it?

Didn't you mean "bright person" ? :P
 (a) Get rid of 'auto'.

removed Jan 1st!
 (b) Create a new keyword that is more obviously read as 'type inference'.

 (c) Create a new keyword that is more obviously read as 'resource
 destruction at end of scope'.

L.
Nov 12 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Lionello Lunesu wrote:
 (a) Get rid of 'auto'.

removed Jan 1st!
 (b) Create a new keyword that is more obviously read as 'type inference'.


My problem with "var" is the history of the keyword. Back in the olden days, there were two main camps of programmers - the Pascal people, and the C people. Each camp looked with disdain upon the other as "not getting it". The Pascal crowd progressed to Modula 2, Object Pascal, and eventually Delphi. The C family progressed to C++, Java, and D. There didn't seem to be much voluntary mixing up, people would switch camps only under duress. So I have a real (possibly outdated) concern that "var" appearing in D will make the language distasteful to the C crowd. The appearance of a language matters a lot, it's like the clothes one wears that identifies one (consciously or not) as being with a particular group. And that's why I've avoided using "var". ("let" is far worse, as it gives the impression that D is some sort of new Basic language.)
 (c) Create a new keyword that is more obviously read as 'resource
 destruction at end of scope'.

L.

Nov 12 2006
next sibling parent reply "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
Walter Bright wrote:

 My problem with "var" is the history of the keyword. Back in the olden days,
 there were two main camps of programmers - the Pascal people, and the C
 people. Each camp looked with disdain upon the other as "not getting it". The
 Pascal crowd progressed to Modula 2, Object Pascal, and eventually Delphi.
 The C family progressed to C++, Java, and D. There didn't seem to be much
 voluntary mixing up, people would switch camps only under duress.
 
 So I have a real (possibly outdated) concern that "var" appearing in D will
 make the language distasteful to the C crowd. The appearance of a language
 matters a lot, it's like the clothes one wears that identifies one
 (consciously or not) as being with a particular group.
 
 And that's why I've avoided using "var".

Well, 'var' is used in C# 3.0 for this purpose (which is obviously a C-family language and a popular one) And it's also used in JavaScript and Scala (which have mostly C-family look and feel) So I think this isn't a serious concern. And as you can see from this and other threads most people here are happy with it except those who seldom use it for variable naming.
 
 ("let" is far worse, as it gives the impression that D is some sort of new
 Basic language.)

Forget about Basic, 'let' is used in ML that pioneered the concept of type inference! And there is also 'def' (from define) (used in Nemerle for this purpose, in many languages indicates function definition). But I'd like to see it short (3-4 characters) otherwise typing 'int' would be simpler :). -- AKhropov
Nov 12 2006
next sibling parent reply "Chris Miller" <chris dprogramming.com> writes:
On Sun, 12 Nov 2006 08:28:51 -0500, Andrey Khropov  
<andkhropov_nosp m_mtu-net.ru> wrote:

 Walter Bright wrote:

 And that's why I've avoided using "var".

Well, 'var' is used in C# 3.0 for this purpose (which is obviously a C-family language and a popular one) And it's also used in JavaScript and Scala (which have mostly C-family look and feel) So I think this isn't a serious concern. And as you can see from this and other threads most people here are happy with it except those who seldom use it for variable naming.

I don't like "var" because it reminds me of a cheap script like JavaScript, but I'm not that against it.
Nov 12 2006
parent reply Ary Manzana <ary esperanto.org.ar> writes:
Chris Miller escribió:
 On Sun, 12 Nov 2006 08:28:51 -0500, Andrey Khropov 
 <andkhropov_nosp m_mtu-net.ru> wrote:
 
 Walter Bright wrote:

 And that's why I've avoided using "var".

Well, 'var' is used in C# 3.0 for this purpose (which is obviously a C-family language and a popular one) And it's also used in JavaScript and Scala (which have mostly C-family look and feel) So I think this isn't a serious concern. And as you can see from this and other threads most people here are happy with it except those who seldom use it for variable naming.

I don't like "var" because it reminds me of a cheap script like JavaScript, but I'm not that against it.

So change "var" into "infer", as others sugested, if the only concern is the name of the keyword. :-) infer x = 2; infer y = new Foo(); I believe it's the most clear syntax: - "auto" -> automatic what? - "var" -> I know it's a variable, so...? - "infer" -> Ah! It's infering the type...
Nov 12 2006
next sibling parent reply "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
Ary Manzana wrote:

 So change "var" into "infer", as others sugested, if the only concern is the
 name of the keyword. :-)
 
 infer x = 2;
 infer y = new Foo();

Khm, 5 characters for such a common keyword is too long (may be 'inf', but inf is a common word for infinity) And 'infer' also looks very close to 'inferior'. -- AKhropov
Nov 12 2006
parent Ary Manzana <ary esperanto.org.ar> writes:
Andrey Khropov escribió:
 Ary Manzana wrote:
 
 So change "var" into "infer", as others sugested, if the only concern is the
 name of the keyword. :-)

 infer x = 2;
 infer y = new Foo();

Khm, 5 characters for such a common keyword is too long (may be 'inf', but inf is a common word for infinity)

What?! I'm not going to time it, but typing "inf", "var", "auto", "infer", "while", "foreach", etc., should take you about the same time. I don't think a char or two make the difference (I don't know wether your concern is typing it or if the source code will have 5 o 6 bytes more). Second, I don't know if it such a common keyword. Look at all these keywords: "while", "static", "class", "interface", "foreach", "override", "alias", "import", "module", "assert" (very, very common!), "continue", "break", and the list goes on (let's not talk about "foreach_reverse" :-P). I think clarity instead of "let's save letters to make our language more compact... but less clear" is better. "interface" has 9 letters, why now change it to "inter"? It's a very common keyword, and we'll save some bytes there.
 And 'infer' also looks very close to 'inferior'.

But "infer" *is* "infer", it's not "inferior". And people would know that "infer" is what it is (at least it's more obvious than "auto"). Just my opinion...
Nov 12 2006
prev sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Ary Manzana wrote:
 Chris Miller escribió:
 
 On Sun, 12 Nov 2006 08:28:51 -0500, Andrey Khropov 
 <andkhropov_nosp m_mtu-net.ru> wrote:

 Walter Bright wrote:

 And that's why I've avoided using "var".

Well, 'var' is used in C# 3.0 for this purpose (which is obviously a C-family language and a popular one) And it's also used in JavaScript and Scala (which have mostly C-family look and feel) So I think this isn't a serious concern. And as you can see from this and other threads most people here are happy with it except those who seldom use it for variable naming.

I don't like "var" because it reminds me of a cheap script like JavaScript, but I'm not that against it.

So change "var" into "infer", as others sugested, if the only concern is the name of the keyword. :-) infer x = 2; infer y = new Foo(); I believe it's the most clear syntax: - "auto" -> automatic what? - "var" -> I know it's a variable, so...? - "infer" -> Ah! It's infering the type...

Wholeheartedly agreed. I really do hope 'var' doesn't make it in... I actually use it /quite a lot/ in my code. Last night, to see what the impact would be, I ran a search through some of my code... and had hundreds of hits for just "var", let alone all the other things with "-var-" in their names because I've assumed it was a safe name. -- Chris Nicholson-Sauls
Nov 12 2006
prev sibling next sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Andrey Khropov wrote:
 Well, 'var' is used in C# 3.0 for this purpose (which is obviously a C-family
 language and a popular one)

C# was designed by a Anders Hjelsberg, who wrote Pascal compilers and designed Delphi.
Nov 12 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Walter Bright wrote:
 Andrey Khropov wrote:
 
 Well, 'var' is used in C# 3.0 for this purpose (which is obviously a 
 C-family
 language and a popular one)

C# was designed by a Anders Hjelsberg, who wrote Pascal compilers and designed Delphi.

Good point. But have you heard *anyone* complain that they don't want to use C# because it's too much like Pascal? --bb
Nov 12 2006
parent Walter Bright <newshound digitalmars.com> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 Andrey Khropov wrote:

 Well, 'var' is used in C# 3.0 for this purpose (which is obviously a 
 C-family
 language and a popular one)

C# was designed by a Anders Hjelsberg, who wrote Pascal compilers and designed Delphi.

Good point. But have you heard *anyone* complain that they don't want to use C# because it's too much like Pascal?

Nope. But I also don't have a billion dollars to spend to convince people to look deeper than a first impression.
Nov 12 2006
prev sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Andrey Khropov wrote:
 Walter Bright wrote:
 
 
("let" is far worse, as it gives the impression that D is some sort of new
Basic language.)

Forget about Basic, 'let' is used in ML that pioneered the concept of type inference!

Forget about ML, 'let' is used in Lisp, the granddaddy of all functional programming languages!
 And there is also 'def' (from define)
 (used in Nemerle for this purpose, in many languages indicates function
 definition).

It's a slightly different meaning -- let in functional programming languages, and def in Nemerle define something that's immutable. But close enough.
 But I'd like to see it short (3-4 characters) otherwise typing 'int' would be
 simpler :).

Indeed.
Nov 12 2006
parent "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
Bill Baxter wrote:

 Forget about ML, 'let' is used in Lisp, the granddaddy of all functional
 programming languages!

Thanks for the enlightment, I'm not that familiar with Lisp. Anyway I associate Basic with this 'Dim' and 'As' things and not 'let'. -- AKhropov
Nov 12 2006
prev sibling next sibling parent reply Carlos Santander <csantander619 gmail.com> writes:
Walter Bright escribió:
 
 My problem with "var" is the history of the keyword. Back in the olden 
 days, there were two main camps of programmers - the Pascal people, and 
 the C people. Each camp looked with disdain upon the other as "not 
 getting it". The Pascal crowd progressed to Modula 2, Object Pascal, and 
 eventually Delphi. The C family progressed to C++, Java, and D. There 
 didn't seem to be much voluntary mixing up, people would switch camps 
 only under duress.
 
 So I have a real (possibly outdated) concern that "var" appearing in D 
 will make the language distasteful to the C crowd. The appearance of a 
 language matters a lot, it's like the clothes one wears that identifies 
 one (consciously or not) as being with a particular group.
 
 And that's why I've avoided using "var".
 
 ("let" is far worse, as it gives the impression that D is some sort of 
 new Basic language.)
 
 

I don't think they're valid concerns (meaning they're subjective, not everyone will have those ideas), but I think we (the D community) just want a way to clearly differentiate both meanings of auto. So, choose any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's move on. Also keep in mind that your option #5 (auto c = Class()) doesn't seem to be a popular proposal (based on what has been said in the ng). -- Carlos Santander Bernal
Nov 12 2006
next sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Carlos Santander wrote:
 I don't think they're valid concerns (meaning they're subjective, not 
 everyone will have those ideas), but I think we (the D community) just 
 want a way to clearly differentiate both meanings of auto. So, choose 
 any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's move 
 on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c = Class()) doesn't seem to 
 be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty clear.
Nov 12 2006
next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Walter Bright wrote:
 Carlos Santander wrote:
 
 I don't think they're valid concerns (meaning they're subjective, not 
 everyone will have those ideas), but I think we (the D community) just 
 want a way to clearly differentiate both meanings of auto. So, choose 
 any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's 
 move on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c = Class()) doesn't seem 
 to be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty clear.

And I'm a bit surprised by your surprise, given that it creates a special case rule for one particular, not-so-common situation, *AND* at the same time breaks static opCall. --bb
Nov 12 2006
parent reply Sean Kelly <sean f4.ca> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 Carlos Santander wrote:

 I don't think they're valid concerns (meaning they're subjective, not 
 everyone will have those ideas), but I think we (the D community) 
 just want a way to clearly differentiate both meanings of auto. So, 
 choose any two words: auto/scope, var/auto, def/scoped, foo/bar, and 
 let's move on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c = Class()) doesn't seem 
 to be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty clear.

And I'm a bit surprised by your surprise, given that it creates a special case rule for one particular, not-so-common situation, *AND* at the same time breaks static opCall.

What is the special case here? int i = 5; // scoped int int* j = new int; // dynamic int MyClass c = MyClass(); // scoped class MyClass d = new MyClass(); // dynamic class The only thing better would be if the ctor syntax applied to concrete types as well. Then templates could almost be generic in how they dealt with types. That said, I do appreciate your concern about static opCall. As a somewhat bizarre suggestion that would break the consistency illustrated above: MyClass c = new(scope) MyClass(); // scoped class MyClass d = new MyClass; // dynamic class I don't really like this, but it would work with the existing placement new syntax and doesn't require any new keywords either. Sean
Nov 12 2006
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Sean Kelly wrote:
 Bill Baxter wrote:
 Walter Bright wrote:
 Carlos Santander wrote:

 I don't think they're valid concerns (meaning they're subjective, 
 not everyone will have those ideas), but I think we (the D 
 community) just want a way to clearly differentiate both meanings of 
 auto. So, choose any two words: auto/scope, var/auto, def/scoped, 
 foo/bar, and let's move on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c = Class()) doesn't 
 seem to be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty clear.

And I'm a bit surprised by your surprise, given that it creates a special case rule for one particular, not-so-common situation, *AND* at the same time breaks static opCall.

What is the special case here? int i = 5; // scoped int int* j = new int; // dynamic int MyClass c = MyClass(); // scoped class MyClass d = new MyClass(); // dynamic class

That doesn't look particularly consistent to me. In one case you have int vs int*, the other case you have MyClass for both. But I could live with it if it weren't for that fact that x = MyClass() already has another meaning in D. --bb
Nov 12 2006
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:ej87h8$10nk$1 digitaldaemon.com...

 What is the special case here?

     int i  = 5;       // scoped int
     int* j = new int; // dynamic int

     MyClass c = MyClass();     // scoped class
     MyClass d = new MyClass(); // dynamic class

My main problem with it (besides not being able to use static opCall, which I do use), is that it's far, far too easy to miss. The first time Walter proposed this .. "syntax," I didn't know what he was proposing until I looked real hard at the code for a minute or two. If you _really_ want to make it obvious that it's a RAII class instance, either use a different keyword, or maybe even recycle the C++ way: MyClass c(params); Not that I'm entirely supporting that syntax, but the "Class name = new Class()" is such a common idiom that introducing the very-similar-looking "Class name = Class()" will only cause confusion.
Nov 12 2006
prev sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Sean Kelly wrote:
 That said, I do appreciate your concern about static opCall.  As a 
 somewhat bizarre suggestion that would break the consistency illustrated 
 above:
 
     MyClass c = new(scope) MyClass(); // scoped class
     MyClass d = new MyClass;          // dynamic class
 
 I don't really like this, but it would work with the existing placement 
 new syntax and doesn't require any new keywords either.

Actually that's not so bizzare at all, because "new" already accepts parameters. http://digitalmars.com/d/memory.html#stackclass With a little magic, you can achieve the same effect, using: MyClass c = new (alloca(MyClass.classinfo.init.length)) MyClass; Now, /that/ is bizzare. It would be very nice IMHO if there was a simpler way to do it, such as var c = new(scope) MyClass;
 
 
 Sean

Nov 12 2006
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Carlos Santander wrote:
 I don't think they're valid concerns (meaning they're subjective, not 
 everyone will have those ideas), but I think we (the D community) just 
 want a way to clearly differentiate both meanings of auto. So, choose 
 any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's 
 move on.

I think the auto/scope is probably the best idea.

That will have some affect on this: int (a) = 3; writefln(a); int (exit) = 9; writefln(exit); which all is currently ok. But with scope as a storage class, this: scope (exit) ; would become ambiguious. Is it an empty scope(exit){} or is it a scoped variable called exit that wasn't initialized? Not a huge deal, but perhaps a reason to consider using 'scoped' for the storage class instead of reusing the 'scope' keyword. --bb
Nov 12 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Bill Baxter wrote:
 Walter Bright wrote:
 I think the auto/scope is probably the best idea.

That will have some affect on this: int (a) = 3; writefln(a); int (exit) = 9; writefln(exit); which all is currently ok. But with scope as a storage class, this: scope (exit) ; would become ambiguious. Is it an empty scope(exit){} or is it a scoped variable called exit that wasn't initialized?

I don't think it'll be ambiguous. scope isn't a type or a function, there is no: static (a) = 3; allowed anyway. The rule would be: scope ( means a scope statement, otherwise scope would be a storage class.
Nov 13 2006
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 Bill Baxter wrote:
 Walter Bright wrote:
 I think the auto/scope is probably the best idea.

That will have some affect on this: int (a) = 3; writefln(a); int (exit) = 9; writefln(exit); which all is currently ok. But with scope as a storage class, this: scope (exit) ; would become ambiguious. Is it an empty scope(exit){} or is it a scoped variable called exit that wasn't initialized?

I don't think it'll be ambiguous. scope isn't a type or a function, there is no: static (a) = 3; allowed anyway.

Ah, I hadn't tried that. I assumed it would be OK, too.
 The rule would be:
     scope (
 means a scope statement, otherwise scope would be a storage class.

Yeh, that works given the above. Whew! --bb
Nov 13 2006
prev sibling next sibling parent reply Nils Hensel <nils.hensel web.de> writes:
Walter Bright schrieb:
 I think the auto/scope is probably the best idea.

I have to agree, even though I was among the first to shout out against "auto". I have changed my mind since. Using a storage class for type inference is an easy and coherent method and since C++ will use "auto" for type inference it isn't such a bad choice after all. Perhaps I got used to it after all. I still think though that it should only mean that. My favourite choice for stack variables would be "local". It's short and completely obvious though I could live with "scope" if you want to avoid a new keyword at all costs. Cheers, Nils
Nov 13 2006
parent Walter Bright <newshound digitalmars.com> writes:
Nils Hensel wrote:
 Using a storage class for type inference is an easy and coherent method
 and since C++ will use "auto" for type inference it isn't such a bad
 choice after all. Perhaps I got used to it after all.

I too think the (future) C++ use of 'auto' for type inference cinches it.
 I still think though that it should only mean that.

At this point, I agree.
Nov 13 2006
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Carlos Santander wrote:
 I don't think they're valid concerns (meaning they're subjective, not 
 everyone will have those ideas), but I think we (the D community) just 
 want a way to clearly differentiate both meanings of auto. So, choose 
 any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's 
 move on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c = Class()) doesn't seem 
 to be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty clear.

Seems I was one of the few who actually sort of liked the proposals. So where do we stand now? I couldn't see much of a consensus. I gather that type inference may remain as is, since it works, is clear (IMO), and doesn't introduce any new keywords. But I'm a bit fuzzy on whether anything was decided for RAII. Most folks seem to dislike the original proposal for two reasons: * It conflicts with static opCall. * It isn't easy to distinguish/grep such a declaration vs. a 'new' declaration. And most seem to favor the addition of a new keyword, probably 'scope' somewhere in the declaration. popular form seems to be: scope MyClass c = new MyClass(); // scoped decl auto scope c = new MyClass(); // inferred scoped decl Is this correct so far? And if so, I'd like to re-iterate my concerns about such a syntax: With the above, the 'scope' identifier is associated with the reference, not the data. Thus, it would be equivalent to: MyClass c = new MyClass(); scope(exit) delete c; This raises a host of issues if such references are reassignable, and in the worst case would mean that scoped data could not be allocated on the stack unless the compiler had some form of escape detection. For example: scope MyClass c = new MyClass(); c = new MyClass(); MyClass d = c; return d; Here, we have a new instance of MyClass that should be destroyed on scope exit (by my understanding). However, c is reassigned to a new instance of MyClass before this occurs. The current result is that the new instance is destroyed instead of the old one and the old one will remain in memory until the next GC collection. Also, 'd' will return a reference to data that no longer exists since it will be destroyed when 'c' goes out of scope. Even worse: scope MyClass c = new MyClass(); scope MyClass d = c; Here, we have two scoped references both referring to the same piece of data, which results in a double-deletion. Therefore, to be implemented correctly and safely, such references must uniquely refer to the underlying data, much like C++'s auto_ptr. Finally: scope int* i = new int; What happens here? Will the compiler disallow the use of 'scope' on non-class types, will 'i' be deleted on scope exit, or will 'scope' simply be ingored? If we are truly to use the 'scope' keyword for RAII objects, I humbly request that the data be flagged instead of the reference. Here are two suggestions for syntax: MyClass c = scope MyClass(); MyClass c = new(scope) MyClass(); Both would allow data to be allocated on the stack without escape detection (or an assumption that the user isn't being evil), and the latter is even almost identical to how alloca is used now. I dislike that both would make class allocation semantically different from concrete type allocation, but anything is better than associating 'scope' with the reference itself, for the reasons illustrated above. Sean
Nov 13 2006
next sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Sean Kelly wrote:
 And most seem to favor the addition of a new keyword, probably 'scope' 
 somewhere in the declaration.  popular form seems to be:
 
     scope MyClass c = new MyClass(); // scoped decl
     auto scope c    = new MyClass(); // inferred scoped decl
 
 Is this correct so far?

Yes.
 And if so, I'd like to re-iterate my concerns 
 about such a syntax:
 
 With the above, the 'scope' identifier is associated with the reference, 
 not the data.  Thus, it would be equivalent to:
 
     MyClass c = new MyClass();
     scope(exit) delete c;

Yes.
 This raises a host of issues if such references are reassignable, and in 
 the worst case would mean that scoped data could not be allocated on the 
 stack unless the compiler had some form of escape detection.  For example:
 
     scope MyClass c = new MyClass();
     c = new MyClass();
     MyClass d = c;
     return d;
 
 Here, we have a new instance of MyClass that should be destroyed on 
 scope exit (by my understanding).  However, c is reassigned to a new 
 instance of MyClass before this occurs.  The current result is that the 
 new instance is destroyed instead of the old one and the old one will 
 remain in memory until the next GC collection.  Also, 'd' will return a 
 reference to data that no longer exists since it will be destroyed when 
 'c' goes out of scope.

That's right. It isn't much different from the C++ code: MyClass c(); MyClass& d = c; return d; // Oops!
 Even worse:
 
     scope MyClass c = new MyClass();
     scope MyClass d = c;
 
 Here, we have two scoped references both referring to the same piece of 
 data, which results in a double-deletion.  Therefore, to be implemented 
 correctly and safely, such references must uniquely refer to the 
 underlying data, much like C++'s auto_ptr.

Right. I hope to improve the static analysis to detect and issue compile time errors for such cases.
 Finally:
 
     scope int* i = new int;
 
 What happens here?  Will the compiler disallow the use of 'scope' on 
 non-class types, will 'i' be deleted on scope exit, or will 'scope' 
 simply be ingored?

scope is ignored for non-reference types.
 If we are truly to use the 'scope' keyword for RAII objects, I humbly 
 request that the data be flagged instead of the reference.  Here are two 
 suggestions for syntax:
 
     MyClass c = scope MyClass();
     MyClass c = new(scope) MyClass();
 
 Both would allow data to be allocated on the stack without escape 
 detection (or an assumption that the user isn't being evil), and the 
 latter is even almost identical to how alloca is used now.  I dislike 
 that both would make class allocation semantically different from 
 concrete type allocation, but anything is better than associating 
 'scope' with the reference itself, for the reasons illustrated above.

It's a good idea, but there's currently no way to flag data itself in this way.
Nov 13 2006
parent Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 
 If we are truly to use the 'scope' keyword for RAII objects, I humbly 
 request that the data be flagged instead of the reference.  Here are 
 two suggestions for syntax:

     MyClass c = scope MyClass();
     MyClass c = new(scope) MyClass();

 Both would allow data to be allocated on the stack without escape 
 detection (or an assumption that the user isn't being evil), and the 
 latter is even almost identical to how alloca is used now.  I dislike 
 that both would make class allocation semantically different from 
 concrete type allocation, but anything is better than associating 
 'scope' with the reference itself, for the reasons illustrated above.

It's a good idea, but there's currently no way to flag data itself in this way.

Hrm... so the compiler would have to do something like generate a dummy variable referencing the class instance and act on that instead, and count on the optimizer to throw away the dummy variable when 'c' isn't reassigned in the enclosing scope. I suppose that could be a bit confusing when debugging... and some might complain about the unpredictable stack frame size or some such. Well darn :-) Sean
Nov 13 2006
prev sibling parent reply Boris Kolar <boris.kolar globera.com> writes:
== Quote from Sean Kelly (sean f4.ca)'s article
      MyClass c = scope MyClass();
      MyClass c = new(scope) MyClass();
 Both would allow data to be allocated on the stack without escape
 detection (or an assumption that the user isn't being evil), and the
 latter is even almost identical to how alloca is used now.

I like the above suggestions. After thinking about it, I'm beginning to wonder if scoped variables are usefull at all. The way I see it, there are three cases, where one might desire scoped variables: 1. Guaranteed, deterministic finalization (mostly disposal of system resources). For example, file should be closed when going out of scope. In this case, it would be better to make File class scoped, not individual variables: auto/scoped/whatever class File { this() { ... } ~this() { close; } } 2. Avoiding garbage collection. This can be accomplished, for example, with custom allocation (stack, for example). We can solve this by allowing a single parameter of type DeterministicAllocator to 'new' keyword in all cases (even if 'new' is not overriden in class). Maybe Allocator should be defined as a 'void* delegate()'. For example: // defined in Phobos and treated as special by compiler typedef void* delegate() DeterministicAllocator; class Foo { // 'new' is NOT defined here } void test() { DeterministicAllocator myOwnAllocator = stackAllocator; Foo foo = new(myOwnAllocator) Foo(); } 3. Some aspects of 'value class' semantics are required. Note that 'scope' or 'auto' didn't solve this problem. The best way to solve this is to make structs more powerful (allow inheritance, possibly even interface implementation, default constructors, destructors, but do NOT allow virtual/overriden methods). For example: struct BigInteger: BigCardinal { ~this() { dispose; } bool negative; } In either case, we don't really need scoped variables at all.
Nov 14 2006
next sibling parent Boris Kolar <boris.kolar globera.com> writes:
== Quote from Boris Kolar (boris.kolar globera.com)'s article
 2. Avoiding garbage collection. This can be accomplished, for example, with
custom
 allocation (stack, for example). We can solve this by allowing a single
parameter
 of type DeterministicAllocator to 'new' keyword in all cases (even if 'new' is
not
 overriden in class). Maybe Allocator should be defined as a 'void* delegate()'.
 For example:
     // defined in Phobos and treated as special by compiler
     typedef void* delegate() DeterministicAllocator;
     class Foo {
         // 'new' is NOT defined here
     }
     void test() {
         DeterministicAllocator myOwnAllocator = stackAllocator;
         Foo foo = new(myOwnAllocator) Foo();
     }

Of course, I forgot about deallocaion, so allocators would be defined as something like: // somewhere in Phobos ... typedef void* delegate() Allocate; typedef void delegate(void*) Deallocate; struct NormalAllocator { Allocate allocate; Deallocate deallocate; } struct DeterministicAllocator { Allocate allocate; Deallocate deallocate; } // in application DeterministicAllocator stack = deterministicStack; void test() { Foo foo = new(stack) Foo(); // foo is destroyed here, because stack is DeterministicAllocator }
Nov 14 2006
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Boris Kolar wrote:
 == Quote from Sean Kelly (sean f4.ca)'s article

 I like the above suggestions. After thinking about it, I'm beginning to wonder
if
 scoped variables are usefull at all. The way I see it, there are three cases,
 where one might desire scoped variables:
 
 1. Guaranteed, deterministic finalization (mostly disposal of system
resources).
 For example, file should be closed when going out of scope. In this case, it
would
 be better to make File class scoped, not individual variables:
     auto/scoped/whatever class File {
         this() { ... }
         ~this() { close; }
     }

Wouldn't you like to be able to return a file object from a function? You wouldn't be able to if all File objects were destroyed as soon as the went out of scope. Anyway, thinking about it, "scoped" is kind of a limited concept. Take one variable in one scope and destroy it as soon as that scope ends. You can't return something like that, you can't really meaningfully assign it to other things that way. A more general concept would be to have something that is guaranteed to run its destructor as soon as there are no outstanding references. That's actually a lot simpler to do than general garbage collection. You just count references. It's exactly what boost::shared_ptr does. GC covers *most* cases where people use shared_ptr in C++ -- and in a much cleaner and potentially more efficient way. But the cases where you want something cleaned up as soon as not in use are not handled so well by GC. This includes "scoped" as one particular case. So what about "counted" instead of "scoped"? I guess this has the same issues as scoped (because scoped is basically just a binary refcount). Namely, do you attach it to the class or to the instance? In any event I think boost::shared_ptr / weak_ptr type functionality would be useful in D, but I don't see how to implement it cleanly as a library without an opAssign to keep track of the reference. --bb
Nov 14 2006
prev sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sun, 12 Nov 2006 20:59:05 +0200, Walter Bright  =

<newshound digitalmars.com> wrote:

 Carlos Santander wrote:
 I don't think they're valid concerns (meaning they're subjective, not=


 everyone will have those ideas), but I think we (the D community) jus=


 want a way to clearly differentiate both meanings of auto. So, choose=


 any two words: auto/scope, var/auto, def/scoped, foo/bar, and let's  =


 move on.

I think the auto/scope is probably the best idea.
 Also keep in mind that your option #5 (auto c =3D Class()) doesn't se=


 to be a popular proposal (based on what has been said in the ng).

I'm a bit surprised at that, but the negative reaction to it is pretty=

 clear.

Well I kind of like it. Unfortunate it breaks the static opCall, so it = would be too confusing to have I think. E.g. Class b; auto c =3D Class(); b =3D Class(); //wha? calls static opCall? The following (shorthand) notation won't have that problem: Class c(); Later new values cannot be assigned to 'c': Class c(10, 2); c =3D new Class; //error You could also use this notation with classes: class Foo { int v =3D 1; Bar b(10); } 'b' is binded to 'Foo', it gets destroyed with it. This notation would = remove the initialization of objects from the constructors to declaratio= n = lines (a nice ability to have sometimes). Which is consistent with = initialization of non-object variables. I think this would be great to have as a shorthand, an *alternative* way= = to create scoped/binded objects.
Nov 14 2006
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Kristian Kilpi wrote:
 On Sun, 12 Nov 2006 20:59:05 +0200, Walter Bright 
 <newshound digitalmars.com> wrote:
 
 The following (shorthand) notation won't have that problem:
 
   Class c();

Does D have the same extern declaration ambiguity as C++? In C++ some compilers at least interpret that to be an extern declaration for a function 'c' that returns a "Class" and takes no parameters. So instead you have to say Class c; I don't know if D suffers from this particular ambiguity or not. --bb
Nov 14 2006
prev sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Carlos Santander wrote:
 Also keep in mind that your option #5 (auto c = Class()) doesn't seem to 
 be a popular proposal (based on what has been said in the ng).

I for one would like it! It's much closer to C++. It hides the "new" and eventually might even be changed to allocate memory using the stack instead of the heap. It will be incompatible with static opCall (which I find hackish anyway) so people will probably ask for a way to add constructors to structs. L.
Nov 13 2006
prev sibling next sibling parent Georg Wrede <georg.wrede nospam.org> writes:
Walter Bright wrote:
 Lionello Lunesu wrote:
 
 (a) Get rid of 'auto'.

I completely agree. The current "auto" can then be tagged as deprecated and removed Jan 1st!
 (b) Create a new keyword that is more obviously read as 'type 
 inference'.

I like "var".

My problem with "var" is the history of the keyword. Back in the olden days, there were two main camps of programmers - the Pascal people, and the C people. Each camp looked with disdain upon the other as "not getting it". The Pascal crowd progressed to Modula 2, Object Pascal, and eventually Delphi. The C family progressed to C++, Java, and D. There didn't seem to be much voluntary mixing up, people would switch camps only under duress.

These are big things, no denying it.
 So I have a real (possibly outdated) concern that "var" appearing in D 
 will make the language distasteful to the C crowd. The appearance of a 
 language matters a lot, it's like the clothes one wears that identifies 
 one (consciously or not) as being with a particular group.
 
 And that's why I've avoided using "var".
 
 ("let" is far worse, as it gives the impression that D is some sort of 
 new Basic language.)

Good point. "let" is a lot worse than var. And still, I used "let" a lot in Scheme. Go figure. But then, the very concept of type inference is not exactly a C concept, and hence it's sort of OK to then have a, er, unforgettable word for it, right? Things have also changed: in the old days it was pretty much Pascal vs C, but today everybody is fluent in a half dozen other languages as well, some of which do use "var". But the biggest thing of all with "var" is, it's only three letters! It's certainly easier to type than "let_the_compiler_freely_infer_the_type_here". <joke>How about "we"? Shorter still. Oh, what does it stand for? Well obviously it's whatever. Can't get much more appropriate.</joke>
 (c) Create a new keyword that is more obviously read as 'resource
 destruction at end of scope'.

I like "scope"


Nov 12 2006
prev sibling next sibling parent Roberto Mariottini <rmariottini mail.com> writes:
Walter Bright wrote:
 My problem with "var" is the history of the keyword. Back in the olden 
 days, there were two main camps of programmers - the Pascal people, and 
 the C people. Each camp looked with disdain upon the other as "not 
 getting it". The Pascal crowd progressed to Modula 2, Object Pascal, and 
 eventually Delphi. The C family progressed to C++, Java, and D. There 
 didn't seem to be much voluntary mixing up, people would switch camps 
 only under duress.
 
 So I have a real (possibly outdated) concern that "var" appearing in D 
 will make the language distasteful to the C crowd. The appearance of a 
 language matters a lot, it's like the clothes one wears that identifies 
 one (consciously or not) as being with a particular group.
 
 And that's why I've avoided using "var".

You are right, your concern is outdated. Take "var" from ECMAScript, so you don't need to get dirty with Pascal (we won't tell anyone). And, maybe, with "var" you can attract some old Pascal programmer. Ciao --- http://www.mariottini.net/roberto/
Nov 13 2006
prev sibling parent Lionello Lunesu <lio lunesu.remove.com> writes:
Walter Bright wrote:
 My problem with "var" is the history of the keyword. Back in the olden 
 days, there were two main camps of programmers - the Pascal people, and 
 the C people. Each camp looked with disdain upon the other as "not 
 getting it". The Pascal crowd progressed to Modula 2, Object Pascal, and 
 eventually Delphi. The C family progressed to C++, Java, and D. There 
 didn't seem to be much voluntary mixing up, people would switch camps 
 only under duress.

On the other hand: D is the right language to bridge that gap! Is there some a priori reason why there are those two groups? Probably not, since in the end they want to achieve the same thing: write a program to fix a problem. You're afraid of turning against the C crowd, but the C crowd is exactly the group that falls over "auto" meaning two things. In fact, they're probably the ones that don't like "auto" meaning anything other than its original C meaning. They should in fact be happy with "var" :) L.
Nov 13 2006
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Derek Parnell wrote:
 On Sat, 11 Nov 2006 10:48:00 -0800, Walter Bright wrote:
 
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:

 class Class { }

 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();

 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean RAII.

 In the future, I'd like the following to work:

 5) auto c = Class();

 which would mean type inference *and* RAII.

Please excuse my bash and amateur crashing in here ... but Walter, for a very intelligent person, why is it that you just don't get it? Type inference and RAII are two distinct, unrelated and orthogonal concepts. Using one keyword in subtly different syntax permutations to indicate both concepts is just plain stupid. In each of the suggested permutations above, the code reader and writer will constantly be thinking "now what's the precise syntax again?" This reminds me of the exact criticism that you have leveled against some C++ constructs, and some syntax changes to D suggested by your supporters. Namely that the subtle differences in syntax variants is a cause of bugs and makes writing code harder - because they are not visually distinct enough for the average person.

I *fully* agree. It comes a few days late, but I still wanted to say it. The irony and mischeviousness of the statement "The auto storage class currently is a *little fuzzy* in meaning" is teeth-grinding(or something). Walter, I hope that by judging the response in this thread you've seen that everyone agrees that these two language concepts should be well separated. There is really no discussion on that. The question to discuss is rather *how* that separations should be (which keywords, etc.). -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Nov 14 2006
next sibling parent reply Boris Kolar <boris.kolar globera.com> writes:
Proposed extensions, that should solve most RAII (and other) problems:

1 Structs
=========


Structs are a lot like classes, except they can NOT:
- have virtual methods
- override inherited methods
(technically: they can't have VMT table)


1.1 Immutable structs
---------------------

In addition to normal structs, immutable structs can be defined with:

  const struct Point {
    int x;
    int y;
  }

They can be constructed as:

  void test() {
    Point p = Point(10, 20); // x = 10, y = 20
    Point p = Point(x: 10, y: 20); // same as above
    p.x = 30; // COMPILER ERROR: Point is immutable
  }


1.2 Structs can have constructor(s) and destructor
--------------------------------------------------

Also, structs may have constructor(s), destructor:

  struct File {
    this() {
      printf("File.this");
    }
    this(char[] name) {
      handle = openFile(name);
      // handle can be modified only in constructor
    }
    ~this() {
      closeFile(handle);
    }
    HANDLE handle;
  }

Invocation is deterministic (at the beginning and end of variable scope):

  void test() {
    File f; // prints "File.this" (default constructor is invoked)
    // destructor of f is called here
  }


1.3 Inheritance and implicit conversions of structs
---------------------------------------------------

Structs can inherit from one or more other structs:

  struct A {
    int a;
  }
  struct B {
    int b;
  }
  struct C: A, B {
    // inherited: int a;
    // inherited: int b;
    int c;
  }

Structs (and classes too) can define implicit conversions:

  // A may be struct, interface, class, ...
  struct D: A {
    // nothing is inherited because implicit conversion is defined
    this.A {
      return A(a: 10);
    }
  }

Inheritance and implicit conversion test:

  void test() {
    C c;
    B b = c; // allowed
    D d;
    A a = d; // allowed
  }


2 Classes
=========


2.1 Explicit implementation of interfaces
-----------------------------------------

Classes can explicitly implement interface methods or whole interfaces:

  interface IFoo {
    void foo();
  }
  interface IBar {
    void bar();
  }
  class Foo: IFoo, IBar {
    // explicitly implement IFoo interface methods
    void IFoo.foo() {
    }
    // explicitly implement interface IBar by delegation
    this.IBar {
      return getBar();
    }
  }


2.2 Value classes
-----------------

Value classes are like ordinary classes, except:
- only constructor or destructor can change class state
- they can not have null value (at least default constructor is called)
- they have deterministic finalization if they implement 'Local'

Example:

  const class Foo: Local {
    this() {
      foo = 5; // foo can be modified (only) in constructor/destructor
    }
    ~this() {
      printf("Foo.~this");
    }
    int foo;
  }
  void test() {
    Foo foo; // foo.foo = 5 (default constructor is invoked, foo can't be null)
    // prints "Foo.~this" and destroys foo here
  }

Value classes can easily support deterministic finalization, because no cycles
are
possible (without hacking, anyway) and simple reference counting is sufficient.


2.3 Custom allocators
---------------------

Custom allocators allow any allocation strategy:

  // in Phobos
  interface Allocator {
    void* allocate(Type type);
    void deallocate(Type type, void* mem);
  }
  // test application
  void test() {
    Foo foo = new(myAllocator) Foo();
    // if Foo is value class and implements 'Local', then foo is deleted here
    // ... else foo is deleted when myAllocator is deleted
  }


3 Summary
=========


It seems that scoped variables are unnecessary, because value classes that
implement 'Local' interface, together with implicit conversions, are sufficient
in all of the following scenarios:

1. Finalization is required:

  const class File: Local {
    ~this() {
      close;
    }
  }

2. Garbage collection must be avoided:

  const class Scoped(T): T, Local {
    this(T object) {
      _object = object;
    }
    this.T {
      return _object;
    }
    private T _object;
  }
  Scoped(T) scoped(T)(T object) {
    return new Scoped!(T)(object);
  }
  class Foo {
    void foo() { ... }
  }
  void test() {
    Foo foo = scoped(new Foo());
    foo.foo();
    // foo is deleted here :)
  }
  void test2() {
    scoped(new Foo()).foo();
    // Foo instance is deleted here too! :D
  }

3. Value class semantics is desired:

  const class Point {
    int x;
    int y;
  }

Another (minor) suggestion is allowing method declarations without '()':

  class Foo: Bar {
    int foo {
      // no ambiguity here, consistent with 'this.Bar' definition
      return 5;
    }
    this.Bar {
      return bar;
    }
    private Bar bar;
  }

Also, get rid of static opCall
Nov 14 2006
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Boris Kolar wrote:
 Proposed extensions, that should solve most RAII (and other) problems:
 
 1 Structs
 =========
 
 
 Structs are a lot like classes, except they can NOT:
 - have virtual methods
 - override inherited methods
 (technically: they can't have VMT table)

While in a certain sense true... I'd really like to avoid the C++ situation where the only difference is where they get allocated. I know that's not quite what you're trying for here, but one thing could lead to another... that said -- continue;
 
 1.1 Immutable structs
 ---------------------
 
 In addition to normal structs, immutable structs can be defined with:
 
   const struct Point {
     int x;
     int y;
   }

Not a bad idea, although one could already accomplish this (I think) just by declaring the variable as const, rather than the type... which is notably more consistant.
 They can be constructed as:
 
   void test() {
     Point p = Point(10, 20); // x = 10, y = 20
     Point p = Point(x: 10, y: 20); // same as above
     p.x = 30; // COMPILER ERROR: Point is immutable
   }

If we can get static struct initializers into the open the same way we've gotten array literals out of static array initializers, then this wouldn't be needed. Instead we could just: # Point p1 = {10, 20} ; # Point p2 = {x:10, y:20} ; Already works, so long as p is declared static/const.
 
 1.2 Structs can have constructor(s) and destructor
 --------------------------------------------------
 
 Also, structs may have constructor(s), destructor:
 
   struct File {
     this() {
       printf("File.this");
     }
     this(char[] name) {
       handle = openFile(name);
       // handle can be modified only in constructor
     }
     ~this() {
       closeFile(handle);
     }
     HANDLE handle;
   }

I'm still undecided on this, to be honest. I don't think its a bad thing, per se, and certainly know of uses for it... but it makes me antsy for some reason. May just be unreasonable paranoia.
 Invocation is deterministic (at the beginning and end of variable scope):
 
   void test() {
     File f; // prints "File.this" (default constructor is invoked)
     // destructor of f is called here
   }

As it likely should be.
 
 1.3 Inheritance and implicit conversions of structs
 ---------------------------------------------------
 
 Structs can inherit from one or more other structs:
 
   struct A {
     int a;
   }
   struct B {
     int b;
   }
   struct C: A, B {
     // inherited: int a;
     // inherited: int b;
     int c;
   }

This I would like to see.
 Structs (and classes too) can define implicit conversions:
 
   // A may be struct, interface, class, ...
   struct D: A {
     // nothing is inherited because implicit conversion is defined
     this.A {
       return A(a: 10);
     }
   }

If nothing else, it is an interesting syntax. It might make a nice alternative to the opCast() method we have now. Might even make opCast() obsolete (especially since opCast() can only provide conversion to a single type).
 Inheritance and implicit conversion test:
 
   void test() {
     C c;
     B b = c; // allowed
     D d;
     A a = d; // allowed
   }

I assume that, given 'struct D: A' then the following: # D d ; // default ctor # A a = d ; // allowed; implicit conversion # d = a ; // error: cannot convert an A into a D. Or in other words, upon conversion, it actually /is/ an A, and no longer a D. Otherwise, this could potentially negate some uses of structs as direct maps into data files.
 
 2 Classes
 =========
 
 
 2.1 Explicit implementation of interfaces
 -----------------------------------------
 
 Classes can explicitly implement interface methods or whole interfaces:
 
   interface IFoo {
     void foo();
   }
   interface IBar {
     void bar();
   }
   class Foo: IFoo, IBar {
     // explicitly implement IFoo interface methods
     void IFoo.foo() {
     }
     // explicitly implement interface IBar by delegation
     this.IBar {
       return getBar();
     }
   }

This I like. :)
 
 2.2 Value classes
 -----------------
 
 Value classes are like ordinary classes, except:
 - only constructor or destructor can change class state
 - they can not have null value (at least default constructor is called)
 - they have deterministic finalization if they implement 'Local'
 
 Example:
 
   const class Foo: Local {
     this() {
       foo = 5; // foo can be modified (only) in constructor/destructor
     }
     ~this() {
       printf("Foo.~this");
     }
     int foo;
   }
   void test() {
     Foo foo; // foo.foo = 5 (default constructor is invoked, foo can't be null)
     // prints "Foo.~this" and destroys foo here
   }
 
 Value classes can easily support deterministic finalization, because no cycles
are
 possible (without hacking, anyway) and simple reference counting is sufficient.

Hm. No opinion.
 
 2.3 Custom allocators
 ---------------------
 
 Custom allocators allow any allocation strategy:
 
   // in Phobos
   interface Allocator {
     void* allocate(Type type);
     void deallocate(Type type, void* mem);
   }
   // test application
   void test() {
     Foo foo = new(myAllocator) Foo();
     // if Foo is value class and implements 'Local', then foo is deleted here
     // ... else foo is deleted when myAllocator is deleted
   }

Not a bad idea. Not sure if I would use it, personally, but not a bad idea.
 
 3 Summary
 =========
 
 
 It seems that scoped variables are unnecessary, because value classes that
 implement 'Local' interface, together with implicit conversions, are sufficient
 in all of the following scenarios:
 
 1. Finalization is required:
 
   const class File: Local {
     ~this() {
       close;
     }
   }

Sure. Currently achieved using 'auto'... no need to go into that mess all over again, of course.
 2. Garbage collection must be avoided:
 
   const class Scoped(T): T, Local {
     this(T object) {
       _object = object;
     }
     this.T {
       return _object;
     }
     private T _object;
   }
   Scoped(T) scoped(T)(T object) {
     return new Scoped!(T)(object);
   }
   class Foo {
     void foo() { ... }
   }
   void test() {
     Foo foo = scoped(new Foo());
     foo.foo();
     // foo is deleted here :)
   }
   void test2() {
     scoped(new Foo()).foo();
     // Foo instance is deleted here too! :D
   }

I'm not so sure I understand how this is "avoiding" GC... it seems to be /enforcing/ it. But its still a fascinating design concept.
 3. Value class semantics is desired:
 
   const class Point {
     int x;
     int y;
   }

If I want value semantics, I'll generally use a struct. Just can't think of cases right off hand where I'd want this.
 Another (minor) suggestion is allowing method declarations without '()':
 
   class Foo: Bar {
     int foo {
       // no ambiguity here, consistent with 'this.Bar' definition
       return 5;
     }
     this.Bar {
       return bar;
     }
     private Bar bar;
   }

Eh, maybe. I would probably still always type them in there. They don't take up much space, and I'm just too used to a pair of ()'s meaning, "Hey this is a function/method!" Also, it makes me think of C# style properties -- and while I would like to see them in D, I don't need constant false hope. ;)
 Also, get rid of static opCall

Just: no. Leave it be. -- Chris Nicholson-Sauls
Nov 14 2006
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Chris Nicholson-Sauls wrote:
 Structs are a lot like classes, except they can NOT:
 - have virtual methods
 - override inherited methods
 (technically: they can't have VMT table)

While in a certain sense true... I'd really like to avoid the C++ situation where the only difference is where they get allocated.

The only difference between struct and class in C++ is the default protection level. In a struct memebers are public by default, for classes they're private by default. That's the only difference. And also the inheritance in structs is public by default, and private for classes. And that's why it's really annoying that you can't generically forward declare a class/struct without knowing which it is. ---foo.h---- class ForwardDeclared; class Foo { ForwardDeclared *f; }; ------------ This fails if ForwardDeclared turns out to be a struct. Grrr. Who cares which it is?! They're the same freaking thing! All you need to know, mr. dumb compiler, is that I've got a pointer, period. (Maybe typename fixes this? Does anyone know?). --bb
Nov 14 2006
prev sibling parent reply Boris Kolar <boris.kolar globera.com> writes:
== Quote from Chris Nicholson-Sauls (ibisbasenji gmail.com)'s article
 2. Garbage collection must be avoided:

   const class Scoped(T): T, Local {
     this(T object) {
       _object = object;
     }
     this.T {
       return _object;
     }
     private T _object;
   }
   Scoped(T) scoped(T)(T object) {
     return new Scoped!(T)(object);
   }
   class Foo {
     void foo() { ... }
   }
   void test() {
     Foo foo = scoped(new Foo());
     foo.foo();
     // foo is deleted here :)
   }
   void test2() {
     scoped(new Foo()).foo();
     // Foo instance is deleted here too! :D
   }


 But its still a fascinating design concept.

Sorry, I expressed my "avoiding GC" idea very unclearly. What I meant was avoiding long GC runs, which occour when the system runs out of memory and a whole bunch of objects is checked for garbage. There are no guarantees about how long such a GC run may take. That's why real-time programs must avoid situations when system must GC unused objects. And by "real-time programs" I don't mean just mission-critical software that lives depend on, but also games and multimedia applications.
 If I want value semantics, I'll generally use a struct.  Just can't think of

 off hand where I'd want this.

Perhaps when you would need a "struct" to override some method. I'd like to see that the only difference between structs and classes is that structs don't have VMT table (and thereforce can't override methods). So, structs are in a sense 'lightweight' classes.
 Also, it makes me think of C# style properties -- and while I would like to see

 I don't need constant false hope.  ;)

I like D-style properties much better :)
 Also, get rid of static opCall


Well, I meant replace it with constructor (for structs). Or it can stay, but no struct can define both constructor and opCall.
Nov 15 2006
parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Boris Kolar wrote:
 == Quote from Chris Nicholson-Sauls (ibisbasenji gmail.com)'s article
 
Also, it makes me think of C# style properties -- and while I would like to see

them in D,
I don't need constant false hope.  ;)

I like D-style properties much better :)

Myself I really dislike D-style properties (as opposed to C# style). Reason #1: delegate ambiguity class Foo { void delegate() m_bar; void delegate() bar() { return m_bar; } void func() { writefln( "..." ); } this() { m_bar = &func; } } void main() { Foo foo = new Foo(); foo.bar(); // call foo.bar, or return the delegate m_bar? } If you think of properties as member variables, then this does not behave as expected - foo.bar() returns the delegate, but does not call it. Thinking of foo.bar as a method that returns a delegate does cause the behaviour make sense, but then it's just shorthand for calling a method, and nothing more. Reason #2: No op*Assign. This is why we have to type array.length = array.length + 1; instead of array.length++; Reason #3: It's one more possible way to write code that just doesn't make sense. I suppose this isn't too bad since programmers tend to shoot for clarity, but I've run into it. writefln = sqrt = 4.0f; // what?!? ... So I see the current property syntax as nothing more than a shorthand for function/method calling. It does not provide a means to wrap code around the getting and setting of member variables or have member variables with inheritance properties, because properties are not member variables they are methods. I am a fast typer - I don't mind the extra 2 parens to call a function. However, being a fast typer does not solve the delegate ambiguity (a bit of thought can, but that's what properties are supposed to save IMO). Also I used C# properties a lot and enjoyed them thoroughly. No problems there. Well that's my case. Could you explain why you prefer D-style properties, please? I'd like to know if there are any significant advantages to having it this way.
Nov 15 2006
parent reply Boris Kolar <boris.kolar globera.com> writes:
== Quote from Chad J (gamerChad _spamIsBad_gmail.com)'s article
 Reason #1: delegate ambiguity
 class Foo
 {
      void delegate() m_bar;
      void delegate() bar() { return m_bar; }
      void func()
      {
          writefln( "..." );
      }
      this()
      {
          m_bar = &func;
      }
 }
 void main()
 {
      Foo foo = new Foo();
      foo.bar(); // call foo.bar, or return the delegate m_bar?
 }
 If you think of properties as member variables, then this does not
 behave as expected - foo.bar() returns the delegate, but does not call
 it.  Thinking of foo.bar as a method that returns a delegate does cause
 the behaviour make sense, but then it's just shorthand for calling a
 method, and nothing more.

You're right, but it seems to me that your example is more of a hypothetical problem than a practical one. Not sold on reason #1 ;)
 Reason #2:
 No op*Assign.  This is why we have to type
 array.length = array.length + 1;
 instead of
 array.length++;

That convinced me. I remember now that I have stumbled on this problem as well. Still, a smart compiler might allow array.length++.
 Reason #3:
 It's one more possible way to write code that just doesn't make sense.
 I suppose this isn't too bad since programmers tend to shoot for
 clarity, but I've run into it.
 writefln = sqrt = 4.0f; // what?!?

That's a good one :) Never thought of that. Although it's merely a bad style - I always assume there are already infinite number of ways to write program in a cryptic style.
 Well that's my case.  Could you explain why you prefer D-style
 properties, please?  I'd like to know if there are any significant
 advantages to having it this way.

Well, I could never decide if a something is just a parameterless function, a property, or a field. In D, it's all used the same way. You can, for example, build an early prototype by using a field and then turn it into a property (that, for example, logs every call). Also, I like the fact that writing the parameterless function is exactly as verbose (not less, as in C#) than writing a read-only property. Also, Eiffel and Wikipedia make some convincing arguments: http://www.eiffel.com/general/monthly_column/2005/Sept_October.html http://en.wikipedia.org/wiki/Uniform_access_principle
Nov 15 2006
parent Chad J <gamerChad _spamIsBad_gmail.com> writes:
Boris Kolar wrote:
 == Quote from Chad J (gamerChad _spamIsBad_gmail.com)'s article
 
Reason #1: delegate ambiguity ...

You're right, but it seems to me that your example is more of a hypothetical problem than a practical one. Not sold on reason #1 ;)

It's practical, I've been bitten by it. Otherwise I probably would have never thought about it.
 
Reason #2:
No op*Assign.  This is why we have to type
array.length = array.length + 1;
instead of
array.length++;

That convinced me. I remember now that I have stumbled on this problem as well. Still, a smart compiler might allow array.length++.

A smart compiler won't save this. That's because it will make the language depend on Quality Of Implementation (QOI). If one were to write code while using said smart compiler, then the code gets moved to a 'dumb' compiler, the code will break if array.length++; was ever used. This trashes the ability to easily port code between compilers.
 
Reason #3:
It's one more possible way to write code that just doesn't make sense.
I suppose this isn't too bad since programmers tend to shoot for
clarity, but I've run into it.
writefln = sqrt = 4.0f; // what?!?

That's a good one :) Never thought of that. Although it's merely a bad style - I always assume there are already infinite number of ways to write program in a cryptic style.
Well that's my case.  Could you explain why you prefer D-style
properties, please?  I'd like to know if there are any significant
advantages to having it this way.

Well, I could never decide if a something is just a parameterless function, a property, or a field. In D, it's all used the same way. You can, for example, build an early prototype by using a field and then turn it into a property (that, for example, logs every call).

You would be able to do that with C# syntax too. You just wouldn't be able to call it like a function. IMO, calling a field is nonsensicle. It's right alongside assigning to a function/method.
 Also, I like the fact that writing the parameterless function is
 exactly as verbose (not less, as in C#) than writing a read-only
 property.
 

Maybe C# properties aren't perfect :) Perhaps we can work on this...
 Also, Eiffel and Wikipedia make some convincing arguments:
 http://www.eiffel.com/general/monthly_column/2005/Sept_October.html
 http://en.wikipedia.org/wiki/Uniform_access_principle

I think that D fails to acheive UAP with the current property syntax. foo.bar++; // implies field. This betrays whether bar is implemented through storage or computation - it is implied that bar is implemented through storage. I'm going to venture an educated guess that Eiffel does not have such opOperateApply type operators. Ditch the ++, --, +=, -=, *=, etc. and UAP is restored. Also: int a = foo.bar(); // implies method Now we know that bar is implemented through computation. One important feature of UAP seems to be that it allows you to change the implementation of any object member without breaking code that uses that member. D fails here, due to the above. Indeed, this is the part I forgot to mention in my earlier post. It is a corollary to Reason#2, and IMO a much more important reason to ditch the current syntax than having to write opOperateAssign the longhand way. C# style syntax does break UAP as well, but I argue that it does not do so in a very damaging way. Suppose you want to change a member from being a field, to being a method. Why? The reason I see is to add extra functionality to the field, as in logging, inheritance, program state update, etc. Another would be to use fields and methods interchangably. The former I find valuable, and C# accomplishes it. The latter I find nonsensicle in many cases (writefln = 2;), and C# prohibits it. Now, suppose you want to change a member from being a method to being a field. Why? I see two reasons. One is to reduce the code size of the method from small to slightly smaller (it was small already since you can reduce almost all functionality by simply writing func() { return m_val; }). The other is to use fields and methods interchangably. I don't see much value in the former, and am still opposed to the latter, so the fact that C# doesn't really support this is fine by me. Another good argument leveled against C# style properties: too much keyword usage. This shouldn't be too difficult to fix. prop int getter() { return myval; } prop void setter( int toAssign ) { myval = toAssign; } Now it has been reduced to one extra keyword, 'prop'. Also, most of the current behaviour of D's properties is maintained. Indeed, these may not necessarily even be in classes or structs, but also modules and functions and other scopes, as they can be nowadays. It also seems to give the compiler all of the information it needs to determine usage in an easy and straightforward fashion. There was also a suggestion to allow methods without parens int foo { return 5; } void main() { writefln( foo ); // prints 5 } No new keyword, but it breaks for setters. hmmmm, maybe something like this for the setters: private int m_assignable; void foo[ int toAssign ] { m_assignable = toAssign; } Or other possibilities: void foo.( int toAssign ) {...} void foo!{ int toAssign } {...} void foo.{ int toAssign } {...} void foo.[ int toAssign ] {...} and so on... Or perhaps the paren-less suggestion above, with an implicit variable defined like in variadic functions. Let's call it _arg. (perhaps it could be prettier?) void foo { m_assignable = _arg; } Perhaps it should be mandated in the above case that the function does not have a return type, in order to help the compiler tell at first glance that it is indeed a setter. I'm sure there are many other possibilities, more than one of which are viable.
Nov 15 2006
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Boris Kolar wrote:
 Proposed extensions, that should solve most RAII (and other) problems:

Heh heh. That's a mighty big claim. :-)
 1 Structs
 =========
 
 
 Structs are a lot like classes, except they can NOT:
 - have virtual methods
 - override inherited methods
 (technically: they can't have VMT table)
 
 
 1.1 Immutable structs
 ---------------------
 
 In addition to normal structs, immutable structs can be defined with:
 
   const struct Point {
     int x;
     int y;
   }
 
 They can be constructed as:
 
   void test() {
     Point p = Point(10, 20); // x = 10, y = 20
     Point p = Point(x: 10, y: 20); // same as above
     p.x = 30; // COMPILER ERROR: Point is immutable
   }

I don't see much point in that really. hahahah get it? Not much Point. yuk yuk yuk yuk yuk yuk. I'll be here all week. But seriously const applied to instances seems sufficient to me. Why restrict the utility of the class in that way? At least you need to find a better example than Point to illustrate your case.
 1.2 Structs can have constructor(s) and destructor
 --------------------------------------------------
 
 Also, structs may have constructor(s), destructor:

I'd like this too -- at least constructors. But Walter is against destructors since (IIUC) it creates complications when passing structs as arguments or when they get created as implicit temporaries by the compiler. Something like that. Anyway, people use static opCall as a constructor now, but it's always annoying to write such a beast (or such beasts since you often write 3 or 4 different versions): static MyStruct opCall(S s, T t, R r) { MyStruct c; with (c) { m_svar = s; m_tvar = t; m_rvar = r; } return c; } That's about as minimal as it can be, but it's still two superfluous lines and a superfluous return type that you wouldn't need in a real constructor. And it may be slightly less efficient if the compiler doesn't optimize assignment well. It could mean a create & copy vs just one in-place creation. And it doesn't declare your intent clearly. It's just a convention. static opCall doesn't necessarily return a new instance of the struct. However, if you add constructors to structs what's the syntax for use going to be? Personally I can't think of anything more natural than MyStruct(a,b,c). So I think it would have to act just like a static opCall. The only difference is you'd be able to write this instead of the above with all it's extra cruft: this(S s, T t, R r) { m_svar = s; m_tvar = t; m_rvar = r; } Destructors I don't know about. The main use case I have is little sentinal structs that do "set_state" in the constructor "reset_state" in the destructor. (A lot of use for that in OpenGL programs). The thing is I think that paradigm is not so clear. The "fire-and-forget" nature of it is useful when programming { auto st = scopedTransform(trans); ... { auto sc = scopedColor(color); ... } } but it's easy for those ... parts to get very long, and it's easy for those scopeTransform thingy's to get buried somewhere in the middle of the scope. And then it's easy for someone to come along and see what looks like a superfluous block and decide to delete the extra {}, creating a hard to find bug. So I actually think something like this may be a better style for D: auto st = tempTransform(trans); scope(exit) st.restore; At least then the maintenance programmer can see clearly that there's a scope exit in the block and thereby know not to delete that extra {}. Plus that's currently valid D code.
   struct File {

Something like a File shouldn't be a struct. If you're going to be doing file IO, then probably the speed hit of having to do one dynamic allocation is not important.
 1.3 Inheritance and implicit conversions of structs
 ---------------------------------------------------
 
 Structs can inherit from one or more other structs:
 
   struct A {
     int a;
   }
   struct B {
     int b;
   }
   struct C: A, B {
     // inherited: int a;
     // inherited: int b;
     int c;
   }

Yeh, this has been suggested before. There was a discussion about it fairly recently. I don't see why this shouldn't be possible.
 Structs (and classes too) can define implicit conversions:
 
   // A may be struct, interface, class, ...
   struct D: A {
     // nothing is inherited because implicit conversion is defined
     this.A {
       return A(a: 10);
     }
   }

Don't know about that. I think implicit conversion would only make sense for pointers to structs. But maybe I'm missing your point.
 2 Classes
 =========
 
 
 2.1 Explicit implementation of interfaces
 -----------------------------------------
 
 Classes can explicitly implement interface methods or whole interfaces:
 
   interface IFoo {
     void foo();
   }
   interface IBar {
     void bar();
   }
   class Foo: IFoo, IBar {
     // explicitly implement IFoo interface methods
     void IFoo.foo() {
     }
     // explicitly implement interface IBar by delegation
     this.IBar {
       return getBar();
     }
   }

So this is just an alternative to 'override'? If so I like it. I find I always end up putting a comments in my code anyway like: /// These implement the IImplementable interface override int foo() {...} override int bar() {...} But if I move around methods those comments can get stale. int IImplementable.foo() { ... } int IImplementable.bar() { ... } would be clearer and eliminate the need for override in most cases. Problem is I think (even though rare) an override can override a method declared in multiple different interfaces.
 2.2 Value classes
 -----------------
 
 Value classes are like ordinary classes, except:
 - only constructor or destructor can change class state
 - they can not have null value (at least default constructor is called)
 - they have deterministic finalization if they implement 'Local'
 
 Example:
 
   const class Foo: Local {
     this() {
       foo = 5; // foo can be modified (only) in constructor/destructor
     }
     ~this() {
       printf("Foo.~this");
     }
     int foo;
   }
   void test() {
     Foo foo; // foo.foo = 5 (default constructor is invoked, foo can't be null)
     // prints "Foo.~this" and destroys foo here
   }
 
 Value classes can easily support deterministic finalization, because no cycles
are
 possible (without hacking, anyway) and simple reference counting is sufficient.

This is just different syntax for "auto class Foo" as far as I can tell.
 2.3 Custom allocators
 ---------------------
 
 Custom allocators allow any allocation strategy:
 
   // in Phobos
   interface Allocator {
     void* allocate(Type type);
     void deallocate(Type type, void* mem);
   }
   // test application
   void test() {
     Foo foo = new(myAllocator) Foo();
     // if Foo is value class and implements 'Local', then foo is deleted here
     // ... else foo is deleted when myAllocator is deleted
   }

I thought this was possible already.
 Another (minor) suggestion is allowing method declarations without '()':

Eh, I don't that as much of a gain, and it would make grepping for function definitions a little bit harder. --bb
Nov 14 2006
parent Boris Kolar <boris.kolar globera.com> writes:
== Quote from Bill Baxter (dnewsgroup billbaxter.com)'s article
(immutable structs)
 But seriously const applied to instances seems sufficient to me.  Why
 restrict the utility of the class in that way?  At least you need to
 find a better example than Point to illustrate your case.

Small utility structs should usually be immutable - it's simply a matter of good design. A few seconds on Google gives enough reasons for immutable structs/classes: http://www-128.ibm.com/developerworks/java/library/j-jtp02183.html
 I'd like this too -- at least constructors.  But Walter is against
 destructors since (IIUC) it creates complications when passing structs
 as arguments or when they get created as implicit temporaries by the
 compiler.  Something like that.

C++ has no problems with destructors, therefore it should be possible to implement them in D as well.
 However, if you add constructors to structs what's the syntax for use
 going to be?  Personally I can't think of anything more natural than
 MyStruct(a,b,c).    So I think it would have to act just like a static
 opCall.

Yes, exactly what I had in mind.
 Something like a File shouldn't be a struct.  If you're going to be
 doing file IO, then probably the speed hit of having to do one dynamic
 allocation is not important.

Of course. But this was not meant to be a real world example. Basically, I don't see much difference between structs and classes except that structs don't have VMT table. Not having VMT table can be (sometimes) usefull, especially if your struct mirrors layout of some other structure. And it makes them a bit "safer", because you can't accidently override struct's methods (which reminds me of another wish: compiler should at least warn when you override methods without explicit 'override').
 Don't know about that.  I think implicit conversion would only make
 sense for pointers to structs.  But maybe I'm missing your point.

Implicit conversions make just as much sense as inheritance. Of course, indirect implicit conversions can be ambigous, but there are algorithms to detect this. For example, consider implicit conversions of "big" versions of numbers: BigCardinal -> BigInteger -> BigRational A relatively simple rule about implicit conversion should be: - implicit conversion is possible if the shortest conversion path to desired type is not ambigous
 So this is just an alternative to 'override'?  If so I like it.  I find
 I always end up putting a comments in my code anyway like:

Explicit implementation is more than just 'override'. You can, for example, implement two different interfaces with the "same" method, like that: interface Foo { int foo(); } interface Bar { char[] foo(); } class FooBar: Foo, Bar { int Foo.foo() { ... } char[] Bar.foo() { ... } } Also, you can implement all methods at once with delegation: class Foo: Bar { this.Bar { // will implement all Bar's methods return getBar(); } }
 Value classes can easily support deterministic finalization, because no cycles
are
 possible (without hacking, anyway) and simple reference counting is sufficient.


Additionally, const classes are immutable, so no cyclic references are possible, therefore implementing deterministic finalization is much easier (for non-const classes, compiler would have to do escape analysis, which I suspect is not an easy task).
 2.3 Custom allocators
 ...
     Foo foo = new(myAllocator) Foo();


Yes, but you have to encode allocation strategy in class. So, in this case, Foo must redefine the 'new' operator. My suggestion was that allocation strategy can be redefined for all (including existing) classes.
 Another (minor) suggestion is allowing method declarations without '()':

function definitions a little bit harder.

Yes, not much gain. Since you can already omit '()' everywhere except in declarations, I thought it would be more consistent to simply state that all '()' are optional.
Nov 15 2006
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter 
 only has meaning for class objects, so let's look at the syntax. 
 There are 4 cases:



Derek Parnell wrote:
 Type inference and RAII are two distinct, unrelated and orthogonal
 concepts. Using one keyword in subtly different syntax permutations to
 indicate both concepts is just plain stupid.


Bruno Medeiros wrote:
 I *fully* agree. It comes a few days late, but I still wanted to say it. 
 The irony and mischeviousness of the statement "The auto storage class 
 currently is a *little fuzzy* in meaning" is teeth-grinding(or 
 something). Walter, I hope that by judging the response in this thread 
 you've seen that everyone agrees that these two language concepts should 
 be well separated. There is really no discussion on that. The question 
 to discuss is rather *how* that separations should be (which keywords, 
 etc.).

I fully agree that they should be made more clearly distinct in the code. But over the past few days I've also come to understand that there is some logic to the status quo. They aren't totally orthogonal concepts when considered in the context of a simple value-type automatic variable. 'auto' for type inference is really just 'auto' for declaring an automatic variable, and the type inference is due to lack of specific type. 'auto' for RAII can be thought of as saying "this thing acts like an automatic variable" in that it's cleaned up just a regular value type would be. int foo = expr(); leaves no traces behind after it's out of scope (because it's an automatic variable). The expression myint foo = expr(); looks like it might also leave no traces behind, but that wouldn't be the case if myint were a Class. So in that case auto myint foo = expr() is saying "Really I mean it! Treat this like a plain-old value-type automatic variable, no matter what it is -- class, struct, or typedef." That said, even though there is a certain kind of logic behind it, it would still be better for the people who have to *write* and *maintain* the code if the distinction were made a little more obvious. --bb
Nov 14 2006
prev sibling next sibling parent Ary Manzana <ary esperanto.org.ar> writes:
Walter Bright escribió:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Is backward compatibility the main restriction that stops you from selecting two keywords distinct from "auto" (and a lot of other unclear stuff)? If it's that, what you can do is propose a final, clean syntax for version 1.0 and get the programmers to update their codes to v1.0. I guess they will do that, at least active projects: old, abandoned projects sure will fail, as probably they fail now with some last language modifications. I think no one but you want's to keep the "auto" keyword. -- Ary
Nov 11 2006
prev sibling next sibling parent Georg Wrede <georg.wrede nospam.org> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.

Well, you know my view here: we need two separate keywords.
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Maybe, when both autotyping and scoped variables are commonplace, we'll eventually start wanting a single word to denote both. That word could be "auto". But in the meantime, two separate words, none of which is auto.
Nov 11 2006
prev sibling next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound digitalmars.com> wrote in message 
news:ej55ss$1g6m$1 digitaldaemon.com...
 The auto storage class currently is a little fuzzy in meaning, it can mean 
 "infer the type" and/or "destruct at end of scope". The latter only has 
 meaning for class objects, so let's look at the syntax. There are 4 cases:

 class Class { }

 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();

 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.

 In the future, I'd like the following to work:

 5) auto c = Class();

No effing way, period. That is unclear as sin. That's like copy constructors in C++. My preference would be a separate keyword which would take the place of the type entirely. It would be treated by the compiler as a type, albeit one which is unknown until the initializer has been semantic'ed. For example, let's call it 'var': var x = 5; var y = "hello"; typeof(x) yields int and typeof(y) yields char[]. This has the nice property of being forward-compatible with more interesting things down the road. How about ATI specialization? var[] x = someFunc(); where x must be an array of any type, which is automatically inferred. It's probably not something that would be that necessary, but it's nice that something like this is possible. Failing a change for ATI, I'll stick with my previously-proposed change for RAII: to use 'scope' as a storage class for a declaration to indicate that it's RAII. scope A a = new A(); scope a2 = new A(); // use ATI since 'scope' functions as a storage class That, or both: scope var a2 = new A(); // RAII and ATI In any case, I think the replies to this thread (and, well, just about every other thread that has EVER been started about this topic) show that you are in a very, very small minority when it comes to ideas about how ATI and RAII should be represented by the syntax. Please do not pull a "just because C++ uses auto for ATI, D should too". D is not going to become a unique language by taking (mis)features from C++ just to appease the nitpicky C++ crowd (which, by now, you should know full well can NEVER be pleased).
Nov 11 2006
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope".

As Don explained to me, 'auto' is a storage class in D and in C along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional). Type inference occurs with the other storage classes as well. I think this is an important distinction because it seems to be a common misconception that 'auto' means 'infer the type of this expression' and that a specific label is necessary for this feature.
 The latter only
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.

This is how I currently understand the syntax to work, and once understood it seems fairly clear. However, I don't like overloading the meaning of keywords if it can be avoided, particularly when both meanings apply to the same keyword used in the same context. Also, I'm not sure I like specifying scoped destruction by modifying the reference variable instead of the data. First, this confuses the idea of reference types in that the references themselves are scoped. Second, this doesn't allow for compilers to create referenced data on the stack as a QOI feature because the auto-destruction quality is attached to the reference, not the data. For example: class MyClass { this( char[] s ) { label = s; } ~this() { printf( "dtor: %.*s\n", label ); } char[] label; } void main() { { auto MyClass c = new MyClass( "a" ); c = new MyClass( "b" ); } printf( "done\n" ); } prints: dtor: b done dtor: a If the current syntax is to be preserved, I would suggest that auto references at least not be reassignable to prevent this behavior.
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

I like this. It is consistent with the declaration of other types in D ('new' means dynamic, otherwise scoped), and it associates scoped destruction with the data rather than with the reference which is exactly as it should be. In fact, if I had any request related to this syntax it would be that the ctor aspect eventually be available for concrete types as well. Not an urgent request as it would be a new feature, but I thought I'd mention it anyway. Also, I don't see any reason to tie stack vs. heap construction to this new syntax. It could remain a QOI feature for compilers as far as I'm concerned. By the way, I assume this change would do away with: auto class MyClass {} as a valid declaration syntax as well? Just wanted to be clear on this. Sean
Nov 11 2006
next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope".

As Don explained to me, 'auto' is a storage class in D and in C along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional).

Interesting. That does kinda make sense when seen in that light. So it does just mean 'an automatic variable' in the traditional K&R sense. Still don't like it. I can understand that there is some logic behind the madness now, but the logic still doesn't seem like a good justification for confusing special cases. I mean given that meaning of auto, "auto Class c = foo()" should have no more implications than than that of "auto int c = foo()". It should mean stack memory is automatic. If you want to clean up the object too, then you need something else, like another 'auto'. So that would be int c = foo(); // automatic stack (normal) Class c = foo(); // automatic stack (normal) auto int c = foo() // automatic statck (normal) auto Class c = foo() // automatic stack (normal) auto c = foo() // automatic stack, type omitted so inferred auto auto Class c = foo() // automatic stack *and* automatic heap auto auto c = foo() // auto stack *and* auto heap *and* type omitted Throwing in the special case rule 'if the thing is an object then you can leave off one auto' just creates confusion.
 In the future, I'd like the following to work:

 5) auto c = Class();

 which would mean type inference *and* RAII.

I like this. It is consistent with the declaration of other types in D ('new' means dynamic, otherwise scoped), and it associates scoped destruction with the data rather than with the reference which is exactly as it should be.

But it is ambiguous with static opCall. That doesn't bother you? This works now, but I don't see how it could with the above: ------ import std.stdio:writefln; class Class { static bool opCall() { return true; } this() { } } void main() { auto a = Class(); auto b = new Class(); writefln("typeof a: ", typeid(typeof(a))); writefln("typeof b: ", typeid(typeof(b))); } ------ --bb
Nov 11 2006
parent Sean Kelly <sean f4.ca> writes:
Bill Baxter wrote:
 Sean Kelly wrote:
 Walter Bright wrote:

 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope".

As Don explained to me, 'auto' is a storage class in D and in C along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional).

Interesting. That does kinda make sense when seen in that light. So it does just mean 'an automatic variable' in the traditional K&R sense. Still don't like it. I can understand that there is some logic behind the madness now, but the logic still doesn't seem like a good justification for confusing special cases. I mean given that meaning of auto, "auto Class c = foo()" should have no more implications than than that of "auto int c = foo()". It should mean stack memory is automatic. If you want to clean up the object too, then you need something else, like another 'auto'.

Agreed.
 In the future, I'd like the following to work:

 5) auto c = Class();

 which would mean type inference *and* RAII.

I like this. It is consistent with the declaration of other types in D ('new' means dynamic, otherwise scoped), and it associates scoped destruction with the data rather than with the reference which is exactly as it should be.

But it is ambiguous with static opCall. That doesn't bother you?

It does. But I'm not sure I prefer the only viable alternative in my mind: MyClass c = scoped MyClass(); (ie. replace 'new' with something else) Sean
Nov 11 2006
prev sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Sean Kelly wrote:
 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope".

As Don explained to me, 'auto' is a storage class in D and in C along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional). Type inference occurs with the other storage classes as well. I think this is an important distinction because it seems to be a common misconception that 'auto' means 'infer the type of this expression' and that a specific label is necessary for this feature.

True. Consider that type inference works in these cases: static a = 3; // a is an int const b = '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just needed because one of the other storage class keywords isn't there.
Nov 12 2006
next sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sun, 12 Nov 2006 12:24:35 +0200, Walter Bright  =

<newshound digitalmars.com> wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it ca=



 mean "infer the type" and/or "destruct at end of scope".



 with 'const' and 'static', so type inference doesn't occur because  =


 'auto' is present so much as because a type is omitted.  The presence=


 of 'auto' merely serves to indicate that the statement is a declarati=


 (since 'auto' is the default storage class and therefore otherwise  =


 optional).  Type inference occurs with the other storage classes as  =


 well.  I think this is an important distinction because it seems to b=


 a common misconception that 'auto' means 'infer the type of this  =


 expression' and that a specific label is necessary for this feature.

True. Consider that type inference works in these cases: static a =3D 3; // a is an int const b =3D '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just needed =

 because one of the other storage class keywords isn't there.

So according to this logic, auto should always mean RAII? E.g. auto c =3D new Class; //RAII If not, then one could argue that static a =3D 3; declares non-static variable, i.e. the static keyword is used for type = inference only (whenever the type is omited).
Nov 12 2006
parent reply Sean Kelly <sean f4.ca> writes:
Kristian Kilpi wrote:
 On Sun, 12 Nov 2006 12:24:35 +0200, Walter Bright 
 <newshound digitalmars.com> wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it 
 can mean "infer the type" and/or "destruct at end of scope".

along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional). Type inference occurs with the other storage classes as well. I think this is an important distinction because it seems to be a common misconception that 'auto' means 'infer the type of this expression' and that a specific label is necessary for this feature.

True. Consider that type inference works in these cases: static a = 3; // a is an int const b = '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just needed because one of the other storage class keywords isn't there.

So according to this logic, auto should always mean RAII? E.g. auto c = new Class; //RAII

Storage class specifiers are really only intended to indicate how the labeled variable (in this case a class reference/pointer) is stored. 'const' places the variable in a special read-only area, 'static' places the variable in static memory, and 'auto' places the variable on the stack. For RAII to apply, the behavior of class references would probably need to change so the referenced value is destroyed when the reference goes out of scope, and this would effectively eliminate any means of returning objects from functions since D objects cannot be passed by value.
 If not, then one could argue that
 
   static a = 3;
 
 declares non-static variable, i.e. the static keyword is used for type 
 inference only (whenever the type is omited).

Not at all. This declares a type-inferred static variable. The type inference occurs because a type is omitted, but the storage class specifier still applies. The same goes for 'const'. Sean
Nov 12 2006
parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sun, 12 Nov 2006 19:02:18 +0200, Sean Kelly <sean f4.ca> wrote:

 Kristian Kilpi wrote:
 On Sun, 12 Nov 2006 12:24:35 +0200, Walter Bright  =


 <newshound digitalmars.com> wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it =





 can mean "infer the type" and/or "destruct at end of scope".





 along with 'const' and 'static', so type inference doesn't occur  =




 because 'auto' is present so much as because a type is omitted.  Th=




 presence of 'auto' merely serves to indicate that the statement is =




 declaration (since 'auto' is the default storage class and therefor=




 otherwise optional).  Type inference occurs with the other storage =




 classes as well.  I think this is an important distinction because =




 seems to be a common misconception that 'auto' means 'infer the typ=




 of this expression' and that a specific label is necessary for this=




 feature.

True. Consider that type inference works in these cases: static a =3D 3; // a is an int const b =3D '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just neede=



 because one of the other storage class keywords isn't there.

E.g. auto c =3D new Class; //RAII

Storage class specifiers are really only intended to indicate how the =

 labeled variable (in this case a class reference/pointer) is stored.  =

 'const' places the variable in a special read-only area, 'static' plac=

 the variable in static memory, and 'auto' places the variable on the  =

 stack.  For RAII to apply, the behavior of class references would  =

 probably need to change so the referenced value is destroyed when the =

 reference goes out of scope, and this would effectively eliminate any =

 means of returning objects from functions since D objects cannot be  =

 passed by value.

So 'auto' in "auto c =3D new Class;" means that 'c' (the variable, not t= he = object referenced by it) is stored in the stack? (That's of course the = case whenever 'static' is not used.) 'auto' has nothing to do when RAII = = should be applied to the referenced object (in princible)?
 If not, then one could argue that
    static a =3D 3;
  declares non-static variable, i.e. the static keyword is used for ty=


 inference only (whenever the type is omited).

Not at all. This declares a type-inferred static variable. The type =

 inference occurs because a type is omitted, but the storage class  =

 specifier still applies.  The same goes for 'const'.


 Sean

Yes, I was trying to point out that 'auto' works inlogically when compar= ed = to other store classes. :) 1a) auto c =3D new Class(); //non-RAII 2a) auto Class c =3D new Class(); //RAII 3a) auto c =3D some_expression(); //non-RAII 4a) auto Class c =3D some_expression(); //RAII Now, lets replace 'auto' with 'static': 1b) static c =3D new Class(); //static 2b) static Class c =3D new Class(); //static 3b) static c =3D some_expression(); //static 4b) static Class c =3D some_expression(); //static Because the cases 1b and 3b currently create static variables, so should= = the cases 1a and 3a create RAII objects. (But because auto does not actually mean RAII, well, it's still confusin= g.)
Nov 12 2006
parent Sean Kelly <sean f4.ca> writes:
Kristian Kilpi wrote:
 On Sun, 12 Nov 2006 19:02:18 +0200, Sean Kelly <sean f4.ca> wrote:
 
 Kristian Kilpi wrote:
 On Sun, 12 Nov 2006 12:24:35 +0200, Walter Bright 
 <newshound digitalmars.com> wrote:
 Sean Kelly wrote:
 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it 
 can mean "infer the type" and/or "destruct at end of scope".

along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional). Type inference occurs with the other storage classes as well. I think this is an important distinction because it seems to be a common misconception that 'auto' means 'infer the type of this expression' and that a specific label is necessary for this feature.

True. Consider that type inference works in these cases: static a = 3; // a is an int const b = '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just needed because one of the other storage class keywords isn't there.

E.g. auto c = new Class; //RAII

Storage class specifiers are really only intended to indicate how the labeled variable (in this case a class reference/pointer) is stored. 'const' places the variable in a special read-only area, 'static' places the variable in static memory, and 'auto' places the variable on the stack. For RAII to apply, the behavior of class references would probably need to change so the referenced value is destroyed when the reference goes out of scope, and this would effectively eliminate any means of returning objects from functions since D objects cannot be passed by value.

So 'auto' in "auto c = new Class;" means that 'c' (the variable, not the object referenced by it) is stored in the stack? (That's of course the case whenever 'static' is not used.) 'auto' has nothing to do when RAII should be applied to the referenced object (in princible)?

Yes. auto MyClass c = new MyClass; currently overloads the meaning of 'auto' to specify that the object referenced by 'c' when 'c' goes out of scope will be deleted. Here, 'auto' isn't really a storage class specifier, although it looks like one.
 If not, then one could argue that
    static a = 3;
  declares non-static variable, i.e. the static keyword is used for 
 type inference only (whenever the type is omited).

Not at all. This declares a type-inferred static variable. The type inference occurs because a type is omitted, but the storage class specifier still applies. The same goes for 'const'.

Yes, I was trying to point out that 'auto' works inlogically when compared to other store classes. :) 1a) auto c = new Class(); //non-RAII 2a) auto Class c = new Class(); //RAII 3a) auto c = some_expression(); //non-RAII 4a) auto Class c = some_expression(); //RAII

Agreed.
 Now, lets replace 'auto' with 'static':
 
 1b) static c = new Class();              //static
 2b) static Class c = new Class();        //static
 3b) static c = some_expression();        //static
 4b) static Class c = some_expression();  //static
 
 Because the cases 1b and 3b currently create static variables, so should 
 the cases 1a and 3a create RAII objects.
 
 (But because auto does not actually mean RAII, well, it's still confusing.)

Yes is is, which is why RAII semantics need to be nailed down before 1.0 in a way that makes sense. Sean
Nov 12 2006
prev sibling parent Georg Wrede <georg.wrede nospam.org> writes:
Walter Bright wrote:
 Sean Kelly wrote:
 
 Walter Bright wrote:

 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope".

As Don explained to me, 'auto' is a storage class in D and in C along with 'const' and 'static', so type inference doesn't occur because 'auto' is present so much as because a type is omitted. The presence of 'auto' merely serves to indicate that the statement is a declaration (since 'auto' is the default storage class and therefore otherwise optional). Type inference occurs with the other storage classes as well. I think this is an important distinction because it seems to be a common misconception that 'auto' means 'infer the type of this expression' and that a specific label is necessary for this feature.

True. Consider that type inference works in these cases: static a = 3; // a is an int const b = '3'; // b is a char So auto doesn't actually ever mean "infer the type", it's just needed because one of the other storage class keywords isn't there.

I think it's okay to "have a word" for "infer the type". Think about it like this: through years C folks have used for(int i=0; i<10; ++i) as the default loop construct, never suspecting how shallow their understanding of it really is. But only people with a deeper understanding could write something like for(Node p=list; p; p=p.next) out of their own head. Similarly, having "a word" for automatic type inference is okay, and it won't become any more a hindrance on your way to become a top programmer than the similar misconception about for. Once you've understood the language enough, you'll figure out that it's simply about not specifying a type and just needing a placeholder in the syntax if no other storage attribute happens to be needed. So, it should be no biggie. --- That would be, IMHO, a better solution than the current, where people instead run in circles chasing wild geese, and even highly admired D gurus like Sean have to ask Don about what the hell is going on here. (I know I should have asked Don!) THAT IS UNACCEPTABLE. It is imperative that the language be designed so that such massive confusion simply does not arise. (I know this post may seem self-contradictory at first reading. :-) )
Nov 12 2006
prev sibling next sibling parent Tom <tom nospam.com> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

No, I don't like it, it's awful. As others, I think two different keywords should be added to separate concepts (I do specially agree with Derek). The 'scope' keyword would be nice for raii ('local' could also work but not so clearly with raii classes). For type inference I like 'infer' as it has been suggested. Regards, -- Tom;
Nov 11 2006
prev sibling next sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.

C'mon man, just introduce the "var" keyword and make everyone happy! <g>
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

eeeh .. ? no no, that's awful!! why would a RAII declaration have no "new"? Is it because it's going to be on the stack? Why don't you instead introduce a special case for "new" to make it allocate on the stack, i.e. var c = new(stack) Class(); //or newStack Class(); //or something else which is a clean straight-forward version of: http://digitalmars.com/d/memory.html#stackclass
Nov 11 2006
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can
 mean "infer the type" and/or "destruct at end of scope". The latter only
 has meaning for class objects, so let's look at the syntax. There are 4
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is
 not used for type inference, i.e. cases (2) and (4), then it does mean
 RAII.

What I would prefer is if you introduced a new keyword that meant "declare". Just that. auto is currently used for type inference not because it MEANS "infer the type" but because it's the default storage class. Currently, declarations look like this: [storage class] [type] [name] We can omit the type if we supply the storage class, or we can omit the storage class if we supply the type. But there's no way to omit both. So I propose that you add a new keyword so that declarations become the following: [declaration] [storage class] [type] [name] This way, we can omit [declaration] if we supply either [storage class] or [type], omit [storage class] if we supply [declaration] or [type], and can omit [type] if we supply [declaration] or [storage type]. Let's say the keyword is chosen to be "def" (being short for "define"). This gives us:
 Class c = new Class();	// normal decl.
 def Class c = new Class();	// as above

 auto Class c = new Class();	// RAII decl.
 def auto Class c = new Class(); // as above

 auto c = new Class();		// RAII with type inference
 def auto c = new Class();	// as above

 def c = new Class();		// type inference with no RAII

Another keyword choice could be "let" (which allows you to "read" the declaration out loud). "var" makes no sense since you could conceivably put it before a "const", and that doesn't make any sense:
 var const x = foo;  // Is it a constant or a variable??

This will let you keep the "auto" keyword, whilst still giving us what we want -- everybody wins!
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Please, no. It breaks static opCall (which I *do* use), and makes no sense. Everywhere else in D requires the "new" keyword; why not for this one particular case? On a related note, I don't suppose I could ask you to take a second look at my old proposal on allowing auto objects to be returned from functions, could I? :P It is one of the very, very few things I'd still like to see in D 1.0. <http://www.digitalmars.com/d/archives/digitalmars/D/38329.html> -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Nov 11 2006
next sibling parent Walter Bright <newshound digitalmars.com> writes:
Daniel Keep wrote:
 On a related note, I don't suppose I could ask you to take a second look
 at my old proposal on allowing auto objects to be returned from
 functions, could I? :P  It is one of the very, very few things I'd still
 like to see in D 1.0.
 
 <http://www.digitalmars.com/d/archives/digitalmars/D/38329.html>

It's an interesting proposal. What I was thinking of eventually for 'auto' is to generalize that it means that the value cannot escape its scope. An auto class member could then be destructed when the class was destructed; an auto function parameter cannot escape the function call, etc. But I haven't really thought about it very far.
Nov 12 2006
prev sibling next sibling parent "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sun, 12 Nov 2006 08:50:51 +0200, Daniel Keep  
<daniel.keep.lists gmail.com> wrote:
[snip]
 On a related note, I don't suppose I could ask you to take a second look
 at my old proposal on allowing auto objects to be returned from
 functions, could I? :P  It is one of the very, very few things I'd still
 like to see in D 1.0.

 <http://www.digitalmars.com/d/archives/digitalmars/D/38329.html>

 	-- Daniel

I especially liked the the 'auto members'. It's not uncommon that member variables of an object are only used by the object (they are binded together forming a compact entity), and they should be destroyed with the object. Currently you have to explicitly delete the member variables in the object's destructor, right? Sometimes I miss value types. They are created and destroyed with the parent object automatically. And basically you're trying to create value types here? Objects are destroyed at the end of scopes, and they are cloned/dublicated in assingments. In reference counting the objects themselves are cloned, the data is refenced. Well, actually the reference counts must be updated in assignments. So, what we actually need for reference counting is an ability to override the assignment operators.
Nov 12 2006
prev sibling parent "Jim Hewes" <jhewesNOSPAM ix.netcom.com> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:ej6g8l$2g20$1 digitaldaemon.com...

 What I would prefer is if you introduced a new keyword that meant
 "declare". Just that. auto is currently used for type inference not
 because it MEANS "infer the type" but because it's the default storage
 class.
 ...
 Let's say the keyword is chosen to be "def" (being short for "define").

I think this is a good suggestion. Although "infer" is good because it says exactly what it's doing, it just sounds a bit odd for a keyword. I like "def" . I agree with the notion that there should be two different keywords. I think "auto" isn't the most descriptive keyword because, as Ary Manzana pointed out, "automatic what?". Using "scope" or "local" for RIAA is probable better for clarity. But if it had to stay as "auto", it wouldn't be the end of the world, either. :) Regarding the original post: Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can
 mean "infer the type" and/or "destruct at end of scope". The latter only
 has meaning for class objects, so let's look at the syntax. There are 4
 cases:

 class Class { }

 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();

 The ambiguity can be resolved by saying that if auto is used for type
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is
 not used for type inference, i.e. cases (2) and (4), then it does mean
 RAII.

I'm not sure people would like having to remember this rule every time they tried to figure out which variables will have their destructors called. Why should explicitly declaring the type of a variable have anything to do with whether it's destructor is called? If I decide to modify my code to "turn on" type inference, I might inadvertently "turn off" the destructor call. Perhaps this came about in an effort to conserve keywords, which is a good goal. That's partly why I asked in my other post if type inference is important: because most people believe it should require another keyword. If you intend to avoid adding another keyword, then perhaps it would be better better for type inference be left out rather than to have the "auto" keyword overloaded as above. (Not that I'm opposed to type inference; I'm not.) Jim
Nov 14 2006
prev sibling next sibling parent Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

I add my vote to the many others who want 'scope' for all cases of RAII.
Nov 12 2006
prev sibling next sibling parent "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sat, 11 Nov 2006 20:48:00 +0200, Walter Bright  =

<newshound digitalmars.com> wrote:

 The auto storage class currently is a little fuzzy in meaning, it can =

 mean "infer the type" and/or "destruct at end of scope". The latter on=

 has meaning for class objects, so let's look at the syntax. There are =

 cases:

 class Class { }

 1) auto c =3D new Class();
 2) auto Class c =3D new Class();
 3) auto c =3D some_expression();
 4) auto Class c =3D some_expression();

 The ambiguity can be resolved by saying that if auto is used for type =

 inference, i.e. cases (1) and (3), then it does not mean RAII. If it i=

 not used for type inference, i.e. cases (2) and (4), then it does mean=

 RAII.

 In the future, I'd like the following to work:

 5) auto c =3D Class();

 which would mean type inference *and* RAII.

I, too, think that we should have new keywords for type inference and RA= II. I like 'var' for type inference. For RAII, I guess 'scope' is ok, even i= f = it's a bit 'funny'; 'scoped' would be better. 'local' would be nice too:= = it's adjective. For example (I use 'scoped' here): var a =3D 1; var int b =3D 2; var c =3D new Class; scoped d =3D new Class; //RAII scoped var e =3D new Class; //RAII What if a RAII keyword could be used with 'new' too? var a =3D new scoped Class; //RAII var b =3D scoped Class; //RAII Well, I think 'auto' would be useful with 'RAII classes' and 'RAII membe= r = variables', if they are implemented in the future. (If a better word = cannot be invented, of course.) E.g. class Foo { auto Bar b; //'b' is automatically destroyed with 'Foo' }
Nov 12 2006
prev sibling next sibling parent Charlie <charlies nowhere.com> writes:
I also am voting the majority, two different words - neither of which 
are auto, 'var' for inference ( as is used allot in modern C family
languages ) , and 'scope' for RAII.

 5) auto c = Class();

Oh the horror!!! Charlie Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

Nov 12 2006
prev sibling next sibling parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

I'd like to see 'auto' remain as it is except for RAII. RAII only makes sense for classes and dynamic arrays, for these 'auto' would only be useful for automatic type inference. E.g: 'auto C c = new C;' is useless and the same as 'C c = new C;' I'd like to see 'scoped' as a new storage class for classes and dynamic arrays. Using it for anything else should be an error. This would mean that 'auto class' would become 'scoped class' too. I'd hate to see 'var', 'let', 'def' etc. introduced as new keywords! Typing time differences for 3-6 letters is in the milliseconds for most coders (I would think) I hope I haven't missed something fundamental, and would be extremely pleased if D 1.0 turns out like this :) *shivers* by the thought of 'var'
Nov 12 2006
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Tomas Lindquist Olsen wrote:
 Walter Bright wrote:

 I'd like to see 'scoped' as a new storage class for classes and dynamic 
 arrays. Using it for anything else should be an error. This would mean 
 that 'auto class' would become 'scoped class' too.

I think scoped int a = expr; should be ok. Allowing that enables you to treat value types and classes uniformly in some template usages. { scoped T a = make_temp_var(); ... } // a has been cleaned up here, whether it was a class or not I don't have a specific use case in mind, but it seems there's no reason to not allow it, since a basic value type acts like it's scoped anyway. --bb
Nov 12 2006
parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 Walter Bright wrote:

 I'd like to see 'scoped' as a new storage class for classes and 
 dynamic arrays. Using it for anything else should be an error. This 
 would mean that 'auto class' would become 'scoped class' too.

I think scoped int a = expr; should be ok. Allowing that enables you to treat value types and classes uniformly in some template usages. { scoped T a = make_temp_var(); ... } // a has been cleaned up here, whether it was a class or not I don't have a specific use case in mind, but it seems there's no reason to not allow it, since a basic value type acts like it's scoped anyway. --bb

Nov 13 2006
prev sibling next sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'

I knew that somehow I couldn't be the only one <g>.
Nov 13 2006
parent reply "JC" <johnch_atms hotmail.com> writes:
"Walter Bright" <newshound digitalmars.com> wrote in message 
news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'

I knew that somehow I couldn't be the only one <g>.

I don't see much wrong with 'var'. It has the nice connotation that it represents a variable, at least. As for RAII, just using a keyword alone doesn't seem to cut it. If references are to be automatically deleted at the end of a scope, that infers that a scope is actually introduced, which to me is signified by a matching pair of curly brackets. I'd like to be able to specify the extent of the scope, perhaps like this: void drawBox(Rectangle rect, Colour colour) { scope (DrawingContext dc = createDrawingContext()) { scope (Pen pen = new Pen(colour)) { dc.drawRectangle(pen, rect); } // pen is freed here } // dc is freed here } Used this way, 'scope' as the RAII keyword makes sense.
Nov 13 2006
next sibling parent reply "Andrey Khropov" <andkhropov_nosp m_mtu-net.ru> writes:
JC wrote:

 void drawBox(Rectangle rect, Colour colour) {
  scope (DrawingContext dc = createDrawingContext()) {
    scope (Pen pen = new Pen(colour)) {
      dc.drawRectangle(pen, rect);
    } // pen is freed here
  } // dc is freed here
 }
 
 Used this way, 'scope' as the RAII keyword makes sense.

Heh, that's exactly how 'using' is used in C#. I prefer usual C++ - like RAII style. -- AKhropov
Nov 13 2006
parent Bill Baxter <wbaxter gmail.com> writes:
Andrey Khropov wrote:
 JC wrote:
 
 
void drawBox(Rectangle rect, Colour colour) {
 scope (DrawingContext dc = createDrawingContext()) {
   scope (Pen pen = new Pen(colour)) {
     dc.drawRectangle(pen, rect);
   } // pen is freed here
 } // dc is freed here
}

Used this way, 'scope' as the RAII keyword makes sense.

Heh, that's exactly how 'using' is used in C#. I prefer usual C++ - like RAII style.

Ugh yes. Please don't force any more extra indentation levels on us! Its bad enough with 'with' already. If you want a new indentation level for every single scoped variable then feel free to make scopes for them all, void drawBox(Rectangle rect, Colour colour) { { scope DrawingContext dc = createDrawingContext(); { scope Pen pen = new Pen(colour); dc.drawRectangle(pen, rect); } // pen is freed here } // dc is freed here } but don't force everyone to do that. --bb
Nov 13 2006
prev sibling parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'


I don't see much wrong with 'var'.

My issue with 'var' is that it looks ugly and doesn't really tell you that RAII is in action.
 It has the nice connotation that it represents a variable, at least.

The other storage classes work for variables too!
 As for RAII, just using a keyword alone doesn't seem to cut it. If 
 references are to be automatically deleted at the end of a scope, that 
 infers that a scope is actually introduced, which to me is signified by a 
 matching pair of curly brackets. I'd like to be able to specify the extent 
 of the scope, perhaps like this:
 
 void drawBox(Rectangle rect, Colour colour) {
   scope (DrawingContext dc = createDrawingContext()) {
     scope (Pen pen = new Pen(colour)) {
       dc.drawRectangle(pen, rect);
     } // pen is freed here
   } // dc is freed here
 }
 
 Used this way, 'scope' as the RAII keyword makes sense. 
 
 

*Please* no!
Nov 13 2006
next sibling parent Tom <tom nospam.com> writes:
== Quote from Tomas Lindquist Olsen (tomas famolsen.dk)'s article
 JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message
 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'


I don't see much wrong with 'var'.

that RAII is in action.

But I think 'var' would mean type inference, not RAII.
 [...]


Nov 13 2006
prev sibling next sibling parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Mon, 13 Nov 2006 19:24:21 +0200, Tomas Lindquist Olsen  =

<tomas famolsen.dk> wrote:

 JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message  =


 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'



My issue with 'var' is that it looks ugly and doesn't really tell you =

 that RAII is in action.

Well that's the point because 'var' isn't used with RAII but with type = inference only. ;) 'var' just tells you that this is a variable declaration, and that's why= I = like it for TI.
 It has the nice connotation that it represents a variable, at least.

The other storage classes work for variables too!
 As for RAII, just using a keyword alone doesn't seem to cut it. If  =


 references are to be automatically deleted at the end of a scope, tha=


 infers that a scope is actually introduced, which to me is signified =


 a matching pair of curly brackets. I'd like to be able to specify the=


 extent of the scope, perhaps like this:
  void drawBox(Rectangle rect, Colour colour) {
   scope (DrawingContext dc =3D createDrawingContext()) {
     scope (Pen pen =3D new Pen(colour)) {
       dc.drawRectangle(pen, rect);
     } // pen is freed here
   } // dc is freed here
 }
  Used this way, 'scope' as the RAII keyword makes sense.

*Please* no!

Also I don't like this syntax. All variables should always be declared a= t = the begining of blocks.
Nov 13 2006
next sibling parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Kristian Kilpi wrote:
 On Mon, 13 Nov 2006 19:24:21 +0200, Tomas Lindquist Olsen 
 <tomas famolsen.dk> wrote:
 
 JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'



My issue with 'var' is that it looks ugly and doesn't really tell you that RAII is in action.

Well that's the point because 'var' isn't used with RAII but with type inference only. ;) 'var' just tells you that this is a variable declaration, and that's why I like it for TI.

Okay seems I misunderstood. Though I dont see why this makes it better. 'auto' as a storage class currently does everything 'var' would do. Only reason this would make sense was if 'auto' was completely removed! Still don't like the look of 'var' though...
 
 It has the nice connotation that it represents a variable, at least.

The other storage classes work for variables too!
 As for RAII, just using a keyword alone doesn't seem to cut it. If 
 references are to be automatically deleted at the end of a scope, 
 that infers that a scope is actually introduced, which to me is 
 signified by a matching pair of curly brackets. I'd like to be able 
 to specify the extent of the scope, perhaps like this:
  void drawBox(Rectangle rect, Colour colour) {
   scope (DrawingContext dc = createDrawingContext()) {
     scope (Pen pen = new Pen(colour)) {
       dc.drawRectangle(pen, rect);
     } // pen is freed here
   } // dc is freed here
 }
  Used this way, 'scope' as the RAII keyword makes sense.

*Please* no!

Also I don't like this syntax. All variables should always be declared at the begining of blocks.

Nov 13 2006
prev sibling parent reply "JC" <johnch_atms hotmail.com> writes:
"Kristian Kilpi" <kjkilpi gmail.com> wrote in message 
news:op.tiyvn2xqusumhd mist...
 It has the nice connotation that it represents a variable, at least.

The other storage classes work for variables too!
 As for RAII, just using a keyword alone doesn't seem to cut it. If 
 references are to be automatically deleted at the end of a scope, that 
 infers that a scope is actually introduced, which to me is signified by 
 a matching pair of curly brackets. I'd like to be able to specify the 
 extent of the scope, perhaps like this:
  void drawBox(Rectangle rect, Colour colour) {
   scope (DrawingContext dc = createDrawingContext()) {
     scope (Pen pen = new Pen(colour)) {
       dc.drawRectangle(pen, rect);
     } // pen is freed here
   } // dc is freed here
 }
  Used this way, 'scope' as the RAII keyword makes sense.

*Please* no!

 Also I don't like this syntax. All variables should always be declared at 
 the begining of blocks.

According to whom? That's a style thing, not a rule.
Nov 13 2006
parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Mon, 13 Nov 2006 20:40:23 +0200, JC <johnch_atms hotmail.com> wrote:

 "Kristian Kilpi" <kjkilpi gmail.com> wrote in message
 news:op.tiyvn2xqusumhd mist...
 It has the nice connotation that it represents a variable, at least.=



 The other storage classes work for variables too!

 As for RAII, just using a keyword alone doesn't seem to cut it. If
 references are to be automatically deleted at the end of a scope, th=



 infers that a scope is actually introduced, which to me is signified=



 a matching pair of curly brackets. I'd like to be able to specify th=



 extent of the scope, perhaps like this:
  void drawBox(Rectangle rect, Colour colour) {
   scope (DrawingContext dc =3D createDrawingContext()) {
     scope (Pen pen =3D new Pen(colour)) {
       dc.drawRectangle(pen, rect);
     } // pen is freed here
   } // dc is freed here
 }
  Used this way, 'scope' as the RAII keyword makes sense.

*Please* no!

 Also I don't like this syntax. All variables should always be declare=


 at
 the begining of blocks.

According to whom? That's a style thing, not a rule.

Yes, that was just my humble opinion. :) I just think that it would be consistent if all the variables will be = declared in the same place. In addition, that would add an extra level o= f = indentation. I would like to write: void func() { int a; scoped file =3D new File; ... } instead of: void func() { int a; scope(file =3D new File) { ... } } And it gets complicated when more than one scoped variable will be used,= = IMHO.
Nov 13 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Kristian Kilpi wrote:
 On Mon, 13 Nov 2006 20:40:23 +0200, JC <johnch_atms hotmail.com> wrote:

 Also I don't like this syntax. All variables should always be 
 declared  at
 the begining of blocks.

According to whom? That's a style thing, not a rule.

Yes, that was just my humble opinion. :) I just think that it would be consistent if all the variables will be declared in the same place.

You're free to have your opinion, but the C++ books I've read disagree with you. The ones I've read advocate declaring variables as close to the point of usage as possible. (Can't remember which books exactly, but probably Stroustrup and/or Meyers' books.) --bb
Nov 13 2006
parent reply "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Mon, 13 Nov 2006 21:17:32 +0200, Bill Baxter <wbaxter gmail.com> wrote:

 Kristian Kilpi wrote:
 On Mon, 13 Nov 2006 20:40:23 +0200, JC <johnch_atms hotmail.com> wrote:

 Also I don't like this syntax. All variables should always be  
 declared  at
 the begining of blocks.

According to whom? That's a style thing, not a rule.

I just think that it would be consistent if all the variables will be declared in the same place.

You're free to have your opinion, but the C++ books I've read disagree with you. The ones I've read advocate declaring variables as close to the point of usage as possible. (Can't remember which books exactly, but probably Stroustrup and/or Meyers' books.) --bb

Hehheh. Ok, I think I understant the point behind that. Well, I guess both the styles have their own advantages and disadvantages. The style where one declares (almost) all the variables at the begining of the (main) block works for me. Sorry for assuming that this style is the Correct Way(TM)... ;)
Nov 13 2006
parent Don Clugston <dac nospam.com.au> writes:
Kristian Kilpi wrote:
 On Mon, 13 Nov 2006 21:17:32 +0200, Bill Baxter <wbaxter gmail.com> wrote:
 
 Kristian Kilpi wrote:
 On Mon, 13 Nov 2006 20:40:23 +0200, JC <johnch_atms hotmail.com> wrote:

 Also I don't like this syntax. All variables should always be 
 declared  at
 the begining of blocks.

According to whom? That's a style thing, not a rule.

I just think that it would be consistent if all the variables will be declared in the same place.

You're free to have your opinion, but the C++ books I've read disagree with you. The ones I've read advocate declaring variables as close to the point of usage as possible. (Can't remember which books exactly, but probably Stroustrup and/or Meyers' books.) --bb

Hehheh. Ok, I think I understant the point behind that. Well, I guess both the styles have their own advantages and disadvantages. The style where one declares (almost) all the variables at the begining of the (main) block works for me. Sorry for assuming that this style is the Correct Way(TM)... ;)

It used to be the only way that worked. Early C compilers couldn't cope with variables declared elsewhere. That restriction is long gone, now.
Nov 13 2006
prev sibling parent reply "JC" <johnch_atms hotmail.com> writes:
"Tomas Lindquist Olsen" <tomas famolsen.dk> wrote in message 
news:eja9o7$2sd4$1 digitaldaemon.com...
 JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'


I don't see much wrong with 'var'.

My issue with 'var' is that it looks ugly and doesn't really tell you that RAII is in action.

Ugliness is in the eye of the beholder. And 'var' was never proposed for RAII.
Nov 13 2006
parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
JC wrote:
 "Tomas Lindquist Olsen" <tomas famolsen.dk> wrote in message 
 news:eja9o7$2sd4$1 digitaldaemon.com...
 JC wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ej9acb$1sac$2 digitaldaemon.com...
 Tomas Lindquist Olsen wrote:
 *shivers* by the thought of 'var'



RAII is in action.

Ugliness is in the eye of the beholder. And 'var' was never proposed for RAII.

is definitely in the eye of the beholder. For me 'var' makes D look like a dynamically typed language, though I'm obviously biased!
Nov 13 2006
prev sibling parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Another argument for using 'auto' for ATI can be making it consistent 
with how it currently works for classes in DMD:

class A
{
	static
	{
		auto x = 2;
		auto y = 42;
	}
	auto z = 27;
}

This works. x and y are static!
Nov 13 2006
parent reply Sean Kelly <sean f4.ca> writes:
Tomas Lindquist Olsen wrote:
 Another argument for using 'auto' for ATI can be making it consistent 
 with how it currently works for classes in DMD:
 
 class A
 {
     static
     {
         auto x = 2;
         auto y = 42;
     }
     auto z = 27;
 }
 
 This works. x and y are static!

I think this works everywhere, as you're free to chain storage classes to your heart's delight: // what is this?? auto const static const static auto x = 5; Sean
Nov 13 2006
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Another argument for using 'auto' for ATI can be making it consistent 
 with how it currently works for classes in DMD:

 class A
 {
     static
     {
         auto x = 2;
         auto y = 42;
     }
     auto z = 27;
 }

 This works. x and y are static!

I think this works everywhere, as you're free to chain storage classes to your heart's delight: // what is this?? auto const static const static auto x = 5; Sean

That does not work: scopetest.d(29): redundant storage class 'const' scopetest.d(29): redundant storage class 'static' scopetest.d(29): redundant storage class 'auto'
Nov 13 2006
parent reply Sean Kelly <sean f4.ca> writes:
Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Another argument for using 'auto' for ATI can be making it consistent 
 with how it currently works for classes in DMD:

 class A
 {
     static
     {
         auto x = 2;
         auto y = 42;
     }
     auto z = 27;
 }

 This works. x and y are static!

I think this works everywhere, as you're free to chain storage classes to your heart's delight: // what is this?? auto const static const static auto x = 5; Sean

That does not work: scopetest.d(29): redundant storage class 'const' scopetest.d(29): redundant storage class 'static' scopetest.d(29): redundant storage class 'auto'

Oh, so you can just do: auto const static x = 5; Could be worse, I suppose. Sean
Nov 13 2006
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Another argument for using 'auto' for ATI can be making it 
 consistent with how it currently works for classes in DMD:

 class A
 {
     static
     {
         auto x = 2;
         auto y = 42;
     }
     auto z = 27;
 }

 This works. x and y are static!

I think this works everywhere, as you're free to chain storage classes to your heart's delight: // what is this?? auto const static const static auto x = 5; Sean

That does not work: scopetest.d(29): redundant storage class 'const' scopetest.d(29): redundant storage class 'static' scopetest.d(29): redundant storage class 'auto'

Oh, so you can just do: auto const static x = 5; Could be worse, I suppose. Sean

It is definitely a bit weird. I would like to see all combinations of these fail. they dont make any sense together. all provide ATI if present. the only problem I can see is if you want to put a constant inside a static block. but maybe that is handled differently? IMHO this would make sense: Invalid: --------- static const x = 5; const static x = 5; const { static x = 5; } any combination of auto and const/static Valid: --------- const x = 5; static x = 5; static { const x = 5; auto x = 5; } const { auto x = 5; } Did I forget any?
Nov 13 2006
parent reply Bill Baxter <wbaxter gmail.com> writes:
Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:
 
 It is definitely a bit weird. I would like to see all combinations of 
 these fail. they dont make any sense together. all provide ATI if 
 present. the only problem I can see is if you want to put a constant 
 inside a static block. but maybe that is handled differently?
 
 IMHO this would make sense:
 
 Invalid:
 ---------
 static const x = 5;

What's wrong with static and const together? One says this is actually store with globals not on the stack, the other says the value isn't going to change. Nothing inconsistent about having those two together.
Nov 13 2006
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:

 It is definitely a bit weird. I would like to see all combinations of 
 these fail. they dont make any sense together. all provide ATI if 
 present. the only problem I can see is if you want to put a constant 
 inside a static block. but maybe that is handled differently?

 IMHO this would make sense:

 Invalid:
 ---------
 static const x = 5;

What's wrong with static and const together? One says this is actually store with globals not on the stack, the other says the value isn't going to change. Nothing inconsistent about having those two together.

distinction? A global const will definitely have static storage. But why not let the compiler decide? I just don't see where having this choice is useful!
Nov 13 2006
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Tomas Lindquist Olsen wrote:
 Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:

 It is definitely a bit weird. I would like to see all combinations of 
 these fail. they dont make any sense together. all provide ATI if 
 present. the only problem I can see is if you want to put a constant 
 inside a static block. but maybe that is handled differently?

 IMHO this would make sense:

 Invalid:
 ---------
 static const x = 5;

What's wrong with static and const together? One says this is actually store with globals not on the stack, the other says the value isn't going to change. Nothing inconsistent about having those two together.

distinction? A global const will definitely have static storage. But why not let the compiler decide? I just don't see where having this choice is useful!

In a function? In a class? --bb
Nov 13 2006
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:

 It is definitely a bit weird. I would like to see all combinations 
 of these fail. they dont make any sense together. all provide ATI if 
 present. the only problem I can see is if you want to put a constant 
 inside a static block. but maybe that is handled differently?

 IMHO this would make sense:

 Invalid:
 ---------
 static const x = 5;

What's wrong with static and const together? One says this is actually store with globals not on the stack, the other says the value isn't going to change. Nothing inconsistent about having those two together.

distinction? A global const will definitely have static storage. But why not let the compiler decide? I just don't see where having this choice is useful!

In a function? In a class? --bb

a static in a class is well defined. so is a const. for me 'static const' reads as having the 'static' redundant. a 'const' in D is by definition static. It cannot change, as only a compile-time constant will qualify, and thus will be the same to all classes of whatever reads it. a function 'const' is very much the same. I fail to come up with a scenario where choosing the storage model for a constant makes any sense! Can you post an example of why we need 'static const' ?
Nov 13 2006
next sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Tomas Lindquist Olsen wrote:
 Can you post an example of why we need 'static const' ?

int foo(int x) { static const i = x; // error, x is not const const j = x; // ok, j is const for duration of foo() call }
Nov 13 2006
next sibling parent reply Lionello Lunesu <lio lunesu.remove.com> writes:
Walter Bright wrote:
 Tomas Lindquist Olsen wrote:
 Can you post an example of why we need 'static const' ?

int foo(int x) { static const i = x; // error, x is not const const j = x; // ok, j is const for duration of foo() call }

Confusing.. I thought const in D meant really 'constant'. If a const in a function can have different values across calls, then I suppose a const for a class can have different value for different instances too? L.
Nov 13 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Lionello Lunesu wrote:
 Confusing.. I thought const in D meant really 'constant'. If a const in 
 a function can have different values across calls, then I suppose a 
 const for a class can have different value for different instances too?

Yes.
Nov 14 2006
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Walter Bright wrote:
 Lionello Lunesu wrote:
 Confusing.. I thought const in D meant really 'constant'. If a const 
 in a function can have different values across calls, then I suppose a 
 const for a class can have different value for different instances too?

Yes.

luck. I think a section going into details on all storage classes would be a good thing! The main problem I have with the D spec is that a lot of stuff is very spread out, and finding the place where the detail you're looking for is, is often pretty hard.
Nov 14 2006
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Tomas Lindquist Olsen wrote:
 
 The main problem I have with the D spec is that a lot of stuff is very 
 spread out, and finding the place where the detail you're looking for 
 is, is often pretty hard.

Agreed. I recommend using the comment page [click the button on the upper right of the spec page] to add cross references to things, and other findings about things that aren't clearly documented. For instance on the operator overload page it doesn't mention opApply, which I think is the natural place you'd go to look for it. But I added a link to where it can be found (statements, under 'foreach') on the comment page. In general I think people should make more use of those comment pages. It's a very nice thing that Walter has added those links to every page of the spec. --bb
Nov 14 2006
parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Bill Baxter wrote:
 Tomas Lindquist Olsen wrote:
 The main problem I have with the D spec is that a lot of stuff is very 
 spread out, and finding the place where the detail you're looking for 
 is, is often pretty hard.

Agreed. I recommend using the comment page [click the button on the upper right of the spec page] to add cross references to things, and other findings about things that aren't clearly documented. For instance on the operator overload page it doesn't mention opApply, which I think is the natural place you'd go to look for it. But I added a link to where it can be found (statements, under 'foreach') on the comment page. In general I think people should make more use of those comment pages. It's a very nice thing that Walter has added those links to every page of the spec. --bb

start using it, and in cases where I find something added appropriate, I will put it in the wiki! Thanx again for the heads up :)
Nov 15 2006
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Walter Bright wrote:
 Tomas Lindquist Olsen wrote:
 Can you post an example of why we need 'static const' ?

int foo(int x) { static const i = x; // error, x is not const const j = x; // ok, j is const for duration of foo() call }

I get "main.d(4): non-constant expression x", with such code: int foo(int x) { //static const i = x; const j = x; // non-constant expression x return 1; } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Nov 14 2006
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Tomas Lindquist Olsen wrote:
 
 a static in a class is well defined. so is a const. for me 'static 
 const' reads as having the 'static' redundant. a 'const' in D is by 
 definition static. It cannot change, as only a compile-time constant 
 will qualify, and thus will be the same to all classes of whatever reads 
 it.
 a function 'const' is very much the same. I fail to come up with a 
 scenario where choosing the storage model for a constant makes any sense!
 Can you post an example of why we need 'static const' ?

Much like "auto", D's "const" is ambiguous, it represents two different concepts: compile time constant. read-only variable(assign only once), same as "final" in Java and C#. You get the first with something like: const int foo = 2; // compile time constant You get the second with: const int foo; this() { foo = 2; } that is, the final-like-const variable (foo here) must be initialized in the constructor of the class/struct or module where it is a member of. So, the compile-time-const does not make sense with "static", but the final-like-const does: --- module test; static const int foo; static this() { foo = 42; } void test() { int a = foo; // Ok foo = 2; // Error "can only initialize const foo inside constructor" // AKA foo is final } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Nov 14 2006
prev sibling parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

I'm going to chime in with the people who don't like (5). I'd much prefer reusing 'scope' or some such.
Nov 12 2006
parent Derek Parnell <derek nomail.afraid.org> writes:
On Mon, 13 Nov 2006 01:58:21 -0500, Chad J wrote:

 Walter Bright wrote:
 The auto storage class currently is a little fuzzy in meaning, it can 
 mean "infer the type" and/or "destruct at end of scope". The latter only 
 has meaning for class objects, so let's look at the syntax. There are 4 
 cases:
 
 class Class { }
 
 1) auto c = new Class();
 2) auto Class c = new Class();
 3) auto c = some_expression();
 4) auto Class c = some_expression();
 
 The ambiguity can be resolved by saying that if auto is used for type 
 inference, i.e. cases (1) and (3), then it does not mean RAII. If it is 
 not used for type inference, i.e. cases (2) and (4), then it does mean 
 RAII.
 
 In the future, I'd like the following to work:
 
 5) auto c = Class();
 
 which would mean type inference *and* RAII.

I'm going to chime in with the people who don't like (5). I'd much prefer reusing 'scope' or some such.

Has anyone worked out how to grep for instances of RAII and/or TI using this proposed syntax? I mean if I wanted to locate all the places where I was using (only) RAII, what would be the regular expression to do that? The same with TI? I'm sure it can be done but I'm no RE guru. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 13/11/2006 6:26:08 PM
Nov 12 2006