Daniel Keep 
|
From the D docs (attribute.html#auto):
"Auto cannot be applied to globals, statics, **data members**, inout or out parameters. Arrays of autos are not allowed, and **auto function return values** are not allowed. Assignment to an auto, other than initialization, is not allowed.
Rationale: **These restrictions may get relaxed in the future if a compelling reason to appears**."
Proposal
========
I'd like to propose the following additions to the abilities of the 'auto' attribute in D:
1. Allow 'auto' function return values, and
2. Allow 'auto' members.
I will try to outline the specifics of these additions, and why I think they would be a valuable addition to D. I ask that you treat the two proposals as being separate, although related.
Also, to try and disambiguate what I mean by 'auto', I will use the following terms:
* auto keyword: the "auto" keyword itself
* auto class: class with the auto keyword in its declaration
* auto variable: a variable that was declared with the auto keyword
* auto instance: an instance of an auto class, or an object instance
that was assigned to an auto variable
Details
=======
Allow 'auto' function return values
-----------------------------------
In the current edition of the D language, you may not return an auto instance from a function. I assume that the rationale behind this decision is simply that: if you can return an auto instance, then you cannot guarantee that the compiler can safely destroy all auto variables at the end of the scope.
I assert that with four simple rules, this problem disappears, allowing you to have auto instance return values.
The rules are:
(1.) You may return an auto instance if it has been created using the 'new' keyword, and not yet assigned to any auto variable. eg:
# return new AutoClass; // This is permitted.
# auto AutoClass a = new AutoClass;
# return a; // This is not permitted.
(2.) You may return an auto instance if it is the result of a function that returns an auto instance. eg:
# auto AutoClass someFunction()
# {
# return new AutoClass;
# }
#
# return someFunction(); // This is permitted.
(3.) If a function returns an auto instance, this instance must either be stored in an auto variable, returned from the current function, or immediately destroyed. eg:
# someFunction();
Implicitly becomes:
# {
# auto AutoClass x = someFunction();
# }
(Alternate 3.) If a function returns an auto instance, this instance must be explicitly stored in an auto variable so that it can be destroyed at scope exit. eg:
# someFunction(); // This is not permitted.
# auto AutoClass x = someFunction(); // It must be written like this
NB: I prefer the first version of Rule #3, but this one might be easier to implement?
(4.) All other forms involving auto instances and return statements are
disallowed. eg:
# auto AutoClass a = new AutoClass;
# return a; // This is not allowed before or after proposal
Rule #1 preserves the compiler's ability to destroy auto variables at scope exit because the newly created object was never assigned to an auto variable: thus it won't be destroyed.
Rule #2 also preserves the ability to destroy auto variables for the same reason.
Rule #3 ensures that objects returned from functions are always destroyed.
A valid question that comes up is: wouldn't it be possible to violate this by passing an auto instance into a function and then returning it?
# auto AutoClass foo(AutoClass bar)
# {
# return bar;
# }
In this case, no it wouldn't. Remember that AutoClass is, well, an auto class, and thus all instances of it are also auto. Not only that, but the return statement does not satisfy either rules 1 or 2. If you wanted to do something like this, you would need to use this idiom:
# auto AutoClass foo(AutoClass bar)
# {
# return bar.dup;
# }
Where dup is a function that creates a new, independent instance, allowing the original to be safely destroyed. You could also do this using *explicit* copy constructors, like so:
# auto AutoClass foo(AutoClass bar)
# {
# return new AutoClass(bar);
# }
#
# auto class AutoClass
# {
# // ...
# this(AutoClass obj)
# {
# // copy state of obj to this new instance
# }
# // ...
# auto AutoClass dup()
# {
# return new AutoClass(this);
# }
# }
Allow 'auto' members
--------------------
From the definition of the auto keyword, it is not immediately apparent what applying the auto keyword to a member would mean.
I propose that we define it to mean this:
"An auto member is a member of an auto class that is declared with the auto keyword. An auto member may ONLY be assigned to from inside the class' constructor, and may only be assigned to once. When the owning object's instance is destroyed, all auto members are also automatically destroyed. It is an error to declare an auto member in a non-auto class."
In other words, it would behave much like a 'const' member. It is worth noting that the previous proposal regarding return values does not allow these auto instances to 'escape' from the object: you still can't directly return the contents of an auto member: you need to dup it first.
An alternate version is:
"An auto member is a member of an auto class that is declared with the auto keyword. **When a non-null auto member is assigned to, the existing auto object is destroyed.** When the owning object's instance is destroyed, all auto members are also automatically destroyed. It is an error to declare an auto member in a non-auto class."
In both cases, auto members would require the same assignment semantics as were used for return statements in the first proposal: that is, you may only assign to auto members if you can prove that the auto instance is not pointed to be anything else.
I am not entirely sure which of the above would be most useful; the
first is perhaps more consistent with the current auto keyword's semantics.
Rationale
=========
The cairo drawing API makes use of pointers to structs as "objects". These objects are reference counted. This is done not only to try to prevent memory leaks, but also because graphics objects can sometimes be very limited, or consume large amounts of memory: being able to deterministically destroy them is a good thing.
When I originally started writing the object-oriented binding for cairo, I had envisaged using auto classes to implement a kind of reference counting system in D. That is, all variables would be auto, and you could get a "reference" to a cairo object by dup'ing the D object wrapping it.
Of course, this fell through when I discovered that you can't return auto instances.
This is not the only place where they would have been useful: there are many cases in Cairo where overloading the constructor is either not feasible, or would result in a massive number of "dummy" classes whose sole purpose is to provide a new constructor. In their place, static factory methods are often used; but since these can't return auto instances, you can't use auto classes at all.
Also, as I hinted at above, this proposal would bring one of the few memory management techniques that D does not yet support into the fold: reference counting. As far as I know, there isn't another language in existence that supports explicit memory management, lazy management with a GC, RAII, scoped destruction AND reference counting.
The proposal regarding auto members is mostly an offshoot of my thinking process: by adding them, we take auto instances from being solely one level-deep, to being arbitrarily deep trees of objects that will be destroyed the instant they are no longer needed, thus making them MUCH more useful.
Summary
=======
I realise it may be a bit late in the game to get this implemented for D 1.0, but I would be happy to simply have it flagged as being "in the next version". It's better to know it's coming eventually, then not to have it at all.
Also, if I've made any silly mistakes in the above, please feel free to correct me :)
-- Daniel Keep
--
v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
|