February 21, 2006
Sean Kelly skrev:
> Fredrik Olsson wrote:
> 
>> After some discussion on #d I though why not put my thoughts into more permanent writing.
>>
>> Keyword auto is used for two reasons; implicit type and making sure the object is destroyed when going out of scope. I suggest a new keyword for the latter: local.
>>
>> local auto foo = new Bar();
> 
> 
> If we're moving towards stack-based auto classes then I'd prefer the distinction be associated with the object and not the reference.  ie.
> 
> auto foo = local Bar();
> 
I see your point, especially with the object later being replaced. Maybe I am trying to shoot to far By arguing for not focusing on "stack-based" but rather on "destroyed when exiting scope".


> I think the distinction is important because foo can be reassigned to a non-local object.  Alternately, simply omitting 'new' entirely might be feasible, though the meaning there is less obvious.  As I said in #d:
> 
> Foo Bar() { return new Foo(); }
> 
> auto foo = Bar();
> 
> looks like a stack-based initialization even though it's not.  But perhaps it doesn't matter in this case, as nothing will break if a heap-based instance is used in place of a stack-based instance, it's replacing things the other direction that can cause problems.
> 
But still I find it could be usefully, especially in a case like this when using a function as a to create the objects. But to solve this I think the distinction should be associated with the assignment, not the variable, nor the object.

Foo Bar() { return new Foo(); }
auto foo = local Bar();
auto baz = local new Baz();

My point still being; that we should not be so focused on how the technical bits like how and where the object is allocated (on stack or heap), but how it should be handled (local to scope or not). If the spec does not specify how things should be done, then the implementation is more free to choose what is best for every case, even if the cases may vary as even more new features are added later on (Hopefully without more syntax revisions).

regards
// Fredrik

February 21, 2006
On Tue, 21 Feb 2006, Fredrik Olsson wrote:

> My point still being; that we should not be so focused on how the technical bits like how and where the object is allocated (on stack or heap), but how it should be handled (local to scope or not). If the spec does not specify how things should be done, then the implementation is more free to choose what is best for every case, even if the cases may vary as even more new features are added later on (Hopefully without more syntax revisions).
> 
> regards
> // Fredrik

I want to focus on the point.  I have to strongly disagree, this sort of thing is what affects ABI's.  If there's a desire to support more than one D compiler, this sort of thing can't be left ambiguous as it would make cross compiler compatibility a nightmare.  A .o/.a/.so generated via dmd would have to successfully link with objects/archives/shared libraries created via other compilers.  That means they'd have to behave the same with respect to anything that leaks out of a compilation unit.

Aspects of this discussion might stay local enough to remain unspecified, if semantics leak outside of a single function, then it needs to be well defined.

Later,
Brad
February 21, 2006
Re auto for implicit typing.
I dont know if C# 3.0 seems to be going in the same direction - but with a
different keyword.
From Language Spec at http://msdn.microsoft.com/vcsharp/future/default.aspx

Implicitly typed local variables

In an implicitly typed local variable declaration, the type of the local variable being declared is inferred from the expression used to initialize the variable. When a local variable declaration specifies var as the type and no type named var is in scope, the declaration is an implicitly typed local variable declaration. For example:

var i = 5; var s = "Hello"; var d = 1.0; var numbers = new int[] {1, 2, 3}; var orders = new Dictionary<int,Order>();

The implicitly typed local variable declarations above are precisely equivalent to the following explicitly typed declarations:

int i = 5; string s = "Hello"; double d = 1.0; int[] numbers = new int[] {1, 2, 3}; Dictionary<int,Order> orders = new Dictionary<int,Order>();

A local variable declarator in an implicitly typed local variable declaration is subject to the following restrictions:

The declarator must include an initializer.
The initializer must be an expression. The initializer cannot be an object or
collection initializer (ยง26.4) by itself, but it can be a new expression that
includes an object or collection initializer.
The compile-time type of the initializer expression cannot be the null type.
If the local variable declaration includes multiple declarators, the
initializers must all have the same compile-time type.
The following are examples of incorrect implicitly typed local variable
declarations:

var x;     // Error, no initializer to infer type from var y = {1, 2, 3}; // Error, collection initializer not permitted var z = null;   // Error, null type not permitted

~~~~~~~~~~~
Sometimes i think it would be useful to take mono's c# front end and put it on
gcc and make it a compiled language. With the additional of auto for stack based
deterministic finalisation for objects.




February 21, 2006
Georg Wrede wrote:
> Mike Capp wrote:
> 
>> In article <dtdb2e$2lsp$1@digitaldaemon.com>, Sean Kelly says...
>>
>>> If we're moving towards stack-based auto classes then I'd prefer
>>> the distinction be associated with the object and not the
>>> reference.  ie.
>>>
>>> auto foo = local Bar();
>>>
>>> I think the distinction is important because foo can be reassigned
>>> to a non-local object.
>>
>>
>> Not currently, it can't. From
>> http://www.digitalmars.com/d/attribute.html#auto : "Assignment to an
>> auto, other than initialization, is not allowed."
> 
> 
> If 'local' were implemented, then it could, since then the meaning of 'auto' would only mean auto-typing and not RAII.

On second thought,

local Bla bla = new Bla();     // RR, heap storage
auto bla = new Bla();          // autotyped, heap storage
Bla bla = new Bla();           // heap storage
local Bla bla = local Bla();   // RR, stack storage
auto bla = local Bla();        // autotyped, stack storage, no RR
Bla bla = local Bla();         // stack storage, no RR

This brings up a few problems. First, the word 'local' is just about as smart as 'auto', i.e. it is misleading and ambiguous for what we're using it for.

Second, do we really need this fine of a control over both storage and disposal?

For the compiler writer, at first sight, keeping track of RR (RAII) here might look like a lot of work. But it actually is ok: "the variable knows" whether to invoke RR, so RR will be invoked irrespective of who happens to be referenced by it.

This may actually open up new ways of using RR?

One potential, hard problem is, this decouples RR-ness from the object instance, making it a property of the reference (the variable). This is obviously not in the spirit of why we have RR in the first place.

----

Unless we can sort out what we want here, I think the current state of RR is adequate -- _except_ that I want another word substituted for 'auto'! We can't have it mean "autotype and/or RAII", at the same time. That is just too much of a disgrace.
February 21, 2006
On Mon, 20 Feb 2006 21:23:26 +0100, Fredrik Olsson <peylow@gmail.com> wrote:
> After some discussion on #d I though why not put my thoughts into more permanent writing.
>
> Keyword auto is used for two reasons; implicit type and making sure the object is destroyed when going out of scope. I suggest a new keyword for the latter: local.
>
> local auto foo = new Bar();
>
> Why? First of auto is only used for the implicit type, so no confusion.   The keyword local in itself describes pretty to the point what is supposed to happen with the variable. And nothing is said about the stack, so we are future proof if in the future we would like to also have:
>
> local auto foo = Bar();
>
> Where Bar(); is a function returning an Object, but we still want the object to be destructed when going out of this scope. The implementation is quite different as the Object would need to be on heap, but the syntax is the same. So local would indicate what should be done (destroy when out of scope), not how it should be done (allocate on stack or whatever).
>
> Even this could be possible, without syntax changes:
> {
>    local Foo bar;
>    // some code
>    Baz(bar); // Jupp Baz have a inout parameter returning an object.
> } // And bar is still destroyed if set to something here...

I thought the plan was to deprecate "auto" WRT declaring stack based auto destructed class instances, resulting in:

class A {}

A a = new A(); //heap alloc
A a = A();     //stack alloc, destruct at scope exit

So, "auto" would only mean "automatic type determination":

auto a = new A(); //heap alloc, 'a' is of type reference to 'A'
auto a = A();     //stack alloc, destruct at scope exit, 'a' is of type reference to 'A'

Regan
February 21, 2006
In article <ops5bhg5ol23k2f5@nrage.netwin.co.nz>, Regan Heath says...
>
>On Mon, 20 Feb 2006 21:23:26 +0100, Fredrik Olsson <peylow@gmail.com> wrote:
>> After some discussion on #d I though why not put my thoughts into more permanent writing.
>>
>> Keyword auto is used for two reasons; implicit type and making sure the object is destroyed when going out of scope. I suggest a new keyword for the latter: local.
>>
>> local auto foo = new Bar();
>>
>> Why? First of auto is only used for the implicit type, so no confusion.
>>   The keyword local in itself describes pretty to the point what is
>> supposed to happen with the variable. And nothing is said about the
>> stack, so we are future proof if in the future we would like to also
>> have:
>>
>> local auto foo = Bar();
>>
>> Where Bar(); is a function returning an Object, but we still want the object to be destructed when going out of this scope. The implementation is quite different as the Object would need to be on heap, but the syntax is the same. So local would indicate what should be done (destroy when out of scope), not how it should be done (allocate on stack or whatever).
>>
>> Even this could be possible, without syntax changes:
>> {
>>    local Foo bar;
>>    // some code
>>    Baz(bar); // Jupp Baz have a inout parameter returning an object.
>> } // And bar is still destroyed if set to something here...
>
>I thought the plan was to deprecate "auto" WRT declaring stack based auto destructed class instances, resulting in:
>
>class A {}
>
>A a = new A(); //heap alloc
>A a = A();     //stack alloc, destruct at scope exit
>
>So, "auto" would only mean "automatic type determination":
>
>auto a = new A(); //heap alloc, 'a' is of type reference to 'A'
>auto a = A();     //stack alloc, destruct at scope exit, 'a' is of type
>reference to 'A'
>
>Regan

are we going to lose static opCall? yikes!


February 21, 2006
Georg Wrede wrote:
> Georg Wrede wrote:
>> Mike Capp wrote:
>>> Sean Kelly says...
>>> 
>>>> If we're moving towards stack-based auto classes then I'd
>>>> prefer the distinction be associated with the object and not
>>>> the reference.  ie.
>>>> 
>>>> auto foo = local Bar();
>>>> 
>>>> I think the distinction is important because foo can be
>>>> reassigned to a non-local object.
>>> 
>>> Not currently, it can't. From http://www.digitalmars.com/d/attribute.html#auto : "Assignment to
>>> an auto, other than initialization, is not allowed."

Currently (D.144) it _is_ allowed. (Obviously a bug.)

>> If 'local' were implemented, then it could, since then the meaning
>> of 'auto' would only mean auto-typing and not RAII.
> 
> On second thought,
> 
> local Bla bla = new Bla();     // RR, heap storage
> auto bla = new Bla();          // autotyped, heap storage
> Bla bla = new Bla();           // heap storage
> local Bla bla = local Bla();   // RR, stack storage
> auto bla = local Bla();        // autotyped, stack storage, no RR
> Bla bla = local Bla();         // stack storage, no RR 

Reordering the lines above might make it clearer:

local Bla bla = new Bla();     // RR, heap storage
local Bla bla = local Bla();   // RR, stack storage
auto bla = new Bla();          // autotyped, heap storage
auto bla = local Bla();        // autotyped, stack storage, no RR
Bla bla = new Bla();           // heap storage
Bla bla = local Bla();         // stack storage, no RR

and consequently also:

local auto bla = new Bla();     // RR, autotyped, heap storage
local auto bla = local Bla();   // RR, autotyped, stack storage

> This brings up a few problems. First, the word 'local' is just about
> as smart as 'auto', i.e. it is misleading and ambiguous for what
> we're using it for.
> 
> Second, do we really need this fine of a control over both storage
> and disposal?
> 
> For the compiler writer, at first sight, keeping track of RR (RAII)
> here might look like a lot of work. But it actually is ok: "the
> variable knows" whether to invoke RR, so RR will be invoked
> irrespective of who happens to be referenced by it.
> 
> This may actually open up new ways of using RR?


Sigh, shouldn't try to think before noon:

> One potential, hard problem is, this decouples RR-ness from the
> object instance, making it a property of the reference (the
> variable). This is obviously not in the spirit of why we have RR in
> the first place.

Ok, RR-ness can be coupled with

 - the reference
 - the assignment
 - the instance
 - the class

Of these, I'd see that instance and class should be made equivalent, since it would be clearer to have separate classes (one requiring RR and the other not) for purposes where _sometimes_ the instance absolutely needs to be RR only. (As opposed to storing knowledge of such a need in an instance variable.)

Currently (D.144) couples RR-ness with the reference. Which is sort of ok, *except* for the fact that one now can assign (e.g.) a global instance to the reference, thus (probably inadvertently) marking it for impending destruction. One can also assign an instance created as RR to (e.g.) a global variable, and then get surprised at the later occurring access violation because the instance got destroyed, even if other references to it exist.

Coupling RR-ness with the assignment is an intriguing alternative. This has the possibility of creating really robust code.

Then the compiler could prevent other assignments to the reference, and it could prevent assignment of the instance to any variable with a longer scope than the original reference.

> ----
> 
> Unless we can sort out what we want here, I think the current state
> of RR is adequate -- _except_ that I want another word substituted
> for 'auto'! We can't have it mean "autotype and/or RAII", at the same
> time. That is just too much of a disgrace.

To summarize:

It would be handy to have a class that _requires_ RR instantiation.

It would also be handy if RR is with the assignment. (That is, forcefully welding the reference and the instance together.)
February 21, 2006
In article <43FAF3AC.2080609@nospam.org>, Georg Wrede says...
>
>> I want another word substituted
>> for 'auto'! We can't have it mean "autotype and/or RAII", at the same
>> time. That is just too much of a disgrace.

Amen.

>To summarize:
>
>It would be handy to have a class that _requires_ RR instantiation.

And it's not that big a leap. Currently I believe you can declare a class "auto" to force all instances to be auto; you'd just have to beef up this rule to say that ONLY instances of auto classes can be declared auto.

This is probably going to get me chased out of town with torches and pitchforks, but I'd actually like to go one step further and rule that ONLY auto classes can define destructors. The thinking being that if you care enough about a managed resource to write a destructor to release it, you almost certainly want that destructor called deterministically. Relying on the garbage collector to call it for you in a timely fashion is almost certainly setting you up for a nasty surprise. Far too many people still seem to think that GC is a panacea for resource management generally, not just memory management, and until they're jolted out of that I don't have much hope for D's RAII support improving.

(Incidentally, what's with this "RR"??? I've never seen it before in 10 years of writing C++. If you mean RAII, it's probably less confusing to the reader to say RAII, however silly an acronym it might be.)

cheers,
Mike


February 21, 2006
Mike Capp wrote:
> Georg Wrede says...
> 
>>> I want another word substituted for 'auto'! We can't have it mean
>>> "autotype and/or RAII", at the same time. That is just too much
>>> of a disgrace.
> 
> Amen.
> 
>> To summarize:
>> 
>> It would be handy to have a class that _requires_ RR instantiation.
> 
> And it's not that big a leap. Currently I believe you can declare a
> class "auto" to force all instances to be auto; you'd just have to
> beef up this rule to say that ONLY instances of auto classes can be
> declared auto.

How about file descriptors and the like? I think there's a lot of stuff that will sometimes be "auto" and sometimes not. It all depends on the local needs in code. Opening a socket in a function call, and passing its reference around while communicating, is an example of where auto would be cumbersome. Then again, another program that opens many sockets for a short while each, might really benefit from a guaranteed short lived socket.

> This is probably going to get me chased out of town with torches and
> pitchforks, but I'd actually like to go one step further and rule
> that ONLY auto classes can define destructors. 

Hmm. This I find a lot more attractive.

> The thinking being
> that if you care enough about a managed resource to write a
> destructor to release it, you almost certainly want that destructor
> called deterministically. Relying on the garbage collector to call it
>  for you in a timely fashion is almost certainly setting you up for a
> nasty surprise. Far too many people still seem to think that GC is a
> panacea for resource management generally, not just memory
> management, and until they're jolted out of that I don't have much
> hope for D's RAII support improving.

Maybe we should solicit for counter examples?
If none are found, then we probably should implement this.

> (Incidentally, what's with this "RR"??? I've never seen it before in
> 10 years of writing C++. If you mean RAII, it's probably less
> confusing to the reader to say RAII, however silly an acronym it
> might be.)

Depends on the reader. ;-)

Check out digitalmars.D:32289.
February 21, 2006
Mike Capp wrote:
> In article <43FAF3AC.2080609@nospam.org>, Georg Wrede says...
>>> I want another word substituted
>>> for 'auto'! We can't have it mean "autotype and/or RAII", at the same
>>> time. That is just too much of a disgrace.
> 
> Amen.
> 
>> To summarize:
>>
>> It would be handy to have a class that _requires_ RR instantiation.
> 
> And it's not that big a leap. Currently I believe you can declare a class "auto"
> to force all instances to be auto; you'd just have to beef up this rule to say
> that ONLY instances of auto classes can be declared auto.
> 
> This is probably going to get me chased out of town with torches and pitchforks,
> but I'd actually like to go one step further and rule that ONLY auto classes can
> define destructors. The thinking being that if you care enough about a managed
> resource to write a destructor to release it, you almost certainly want that
> destructor called deterministically. 

You're saying, abolish finalisers from the language. Radical.
But I agree. I have NEVER seen a single good use for a finaliser. I've only ever seen them used as "poor man's destructors". But I'll change my mind if anyone can show a use for them. Any takers?

I bet removing finalisers would simplify the gc.

However, there's still the issue of manual memory management. It would I think be possible to allow RAII classes to be created on the heap with new, and have the destructor called manually with delete. Whenever the gc runs, if it finds that it is able to collect an object which has a destructor, instead of calling it as a finaliser, it should assert -- a memory leak bug has been found.
Alternatively, you could just use the C++ method and and perform the check only at the end of the program. (But it would be cool to have a function checkForMemoryLeaks() which could be run at any time, for anyone who still wants to use manual memory management. By using mark-and-sweep, you can detect a memory leak much earlier than in C/C++).

Of course, if RAII classes on the heap are forbidden, it's easy -- the GC then never has to worry about destructors or finalisers, it can just release memory.

Relying on the garbage collector to call it
> for you in a timely fashion is almost certainly setting you up for a nasty
> surprise. Far too many people still seem to think that GC is a panacea for
> resource management generally, not just memory management, and until they're
> jolted out of that I don't have much hope for D's RAII support improving.

Agreed.

 > (Incidentally, what's with this "RR"??? I've never seen it before in 10 years of
> writing C++. If you mean RAII, it's probably less confusing to the reader to say
> RAII, however silly an acronym it might be.)

You could think of RAII as "Release At Imminent Incineration" <g>
Or come up with a better interpretation of the letters.

> 
> cheers,
> Mike
> 
>