With statement become like C#'s using?

Bosak bosak at gmail.com
Mon Aug 5 10:45:23 PDT 2013


On Monday, 5 August 2013 at 15:38:12 UTC, Dicebot wrote:
> On Monday, 5 August 2013 at 15:30:45 UTC, Bosak wrote:
>> ...
>
> What you propose is rather unwelcome for classes (destruction 
> of GC-managed objects is non-deterministic) and closest thing 
> for IDisposable D has is "destroy" which is not something that 
> is expected to be called silently.
>
> However, I do like proposed extension of `with` syntax to allow 
> declarations. It perfectly matches `if` and allows to emulate 
> C# behavior via `scoped`. That will improve language 
> consistency.

Oh yes using scoped to achieve that is a good solution. So if I 
write
with(File file = open("filename"))
{
     //setup file
     type = Types.Text; //etc.
}
string text = file.read(); //file still usable after with, but 
explicitly
And if I write the scoped version:
with(scoped!File file = open("filename"))
{
     //retrieve data from file or whatever
}
//file is out of scope and is not usable after

You say that D's destroy is not like C#'s IDisposable. Then why 
doesn't D then declare that kind of interface:
interface Disposable {
     void dispose();
}
And include it in the object module? That way some classes can 
implement this dispose method that will just dispose any used 
resources(and not to replace destructor's role). It is a very 
small(but core) change that is even not connected with the 
compiler, but only with phobos.
For example std file structs can just implement the interface 
like this:
//...in File class/struct that implements Disposable
void dispose() {
     this.close();
}

And if you don't like the idea of adding an interface to the core 
module, then the same thing could be achieved if a special 
opDispose function is declared. This is a more D-way of doing it, 
since there exist opApply that is used only in the foreach 
construct and the opCall that is used to call classes like 
functions.

And then the with implementation is mostly straightforward. 
Depending on weather the declared variable is scoped or not, with 
behaves differently. If it is scoped it first checks if the 
object has dispose/opDispose method in it calls it and then 
destroys(or whatever the compiler does to scoped variables) it. 
And if it is not scoped then it doesn't dispose it and it acts 
just like with acts now(just the ability to declare the variable 
right in the with statement).

That way you explicitly specify that the variable is scoped and 
you know that it will be destroyed when it goes out of scope. In 
addition to that it dipposes "savely".

Maybe opDispose shouldn't be only used in with statement, but 
EVERYWHERE a scoped variable is declared? Here is a more complete 
example:

class Resource { //can be any resource from files to streams to 
anything
     Resource[] used;

     void opDispose() {
         writeln("Resource disposed!");
         //in opDispose the resource should dispose all it's 
resources too
         foreach(res; used)
             res.opDispose();
     }

     static Resource open(string name){
         return new Resource;
     }
}

with(auto resource = Resource.open("res1")){
     //set properties of resource and call setup/init functions
}
resource.doStuff(); //use resource later too
resource.opDispose(); //you can manually dispose it

//or a scoped variant:
string[] data;
with(scoped!Resource res = Resource.open("res2")){
     data = res.getData();
}//res gets out of scope and opDispose is called

if(cond){
     scoped!Resource res = Resource.open("res3");
     //do sth with res
}//get out of scope opDispose gets called and res gets destroyed

I think this dispose thing should be added to D, because it is a 
very common practice in C#(and not only). In the book I used to 
learn C# long ago I remember how they sayed like 100 of times: 
"If you use an object that implements IDisposable ALLWAYS use it 
in an using statement". It is not a strange or not-intuitive 
feature. In fact it can make the "scoped" variables idea more 
popular. And instead of explicitly adding an using statement you 
just declare your variable as scoped and the compiler takes care 
of calling it's dispose automatically when it gets out of scope.

I think that's everything for now.


More information about the Digitalmars-d mailing list