www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - With statement become like C#'s using?

reply "Bosak" <bosak gmail.com> writes:
In C# there is this using construct:

using(Bitmap image = this.OpenImage("filename.bmp")) {
     image.Name = "foo";
     //use image like image.sth
}

which is translated to:

{
     Bitmap image = this.OpenImage("filename.bmp");
     try {
         image.Name = "foo";
         //use image like image.sth
     }
     finally {
         IDisposable obj = image as IDisposable;
         if(obj != null)
             obj.Dispose();
     }
}

I know that the with statement is different, but it can be 
improved so that you can declare things in it like an using 
statement:

with(Bitmap image = open("filename.bmp")) {
     name = "foo";
     //no need to specify image.sth
}

or even a more implicit one:
with(open("filename.bmp")) {
//ditto
}

And both of the above to be translated to:

{
     Bitmap temp = expression;
     //use bitmap
     delete temp; // Call destructor/finallizer of the object
     //I'm not sure if delete was the proper way to call a 
destructor in D
}

And I hope you got the point. Tell me what you think.
Aug 05 2013
next sibling parent "Michal Minich" <michal.minich gmail.com> writes:
On Monday, 5 August 2013 at 12:40:26 UTC, Bosak wrote:
 In C# there is this using construct:

just declare variable as scope, and ti will be destructed as son as function exits. void foo () { scope obj = new Object; } // obj will be destructed here you can also use it together with anonymous scope (same as c#) more generally, there is a "scope" statement http://dlang.org/exception-safe.html that can be used where normally try/finally (without catch) would be used, to achieve cleaner code.
Aug 05 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Michal Minich:

 void foo ()
 {
    scope obj = new Object;
 } // obj will be destructed here

That usage of scope has being deprecated... For Walter: I suggest dmd to give a deprecation message where you use one of the many deprecated D features, like scope classes, floating point comparison operators, and so on. Otherwise D programmers will use those featueres in their code today, and when those feature become deprecated, those people will become angry because of too much code to modify/fix. Bye, bearophile
Aug 05 2013
prev sibling next sibling parent "Michal Minich" <michal.minich gmail.com> writes:
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:
 Michal Minich:

 void foo ()
 {
   scope obj = new Object;
 } // obj will be destructed here

That usage of scope has being deprecated...

I like it use together with scope classes: scope class C {} - are they too deprecated?
Aug 05 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:
 Michal Minich:

 void foo ()
 {
   scope obj = new Object;
 } // obj will be destructed here

That usage of scope has being deprecated... For Walter: I suggest dmd to give a deprecation message where you use one of the many deprecated D features, like scope classes, floating point comparison operators, and so on. Otherwise D programmers will use those featueres in their code today, and when those feature become deprecated, those people will become angry because of too much code to modify/fix. Bye, bearophile

It's not a feature I've ever had the need for so far, but what is the replacement for scope?
Aug 05 2013
prev sibling next sibling parent "Bosak" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 12:49:11 UTC, Michal Minich wrote:
 On Monday, 5 August 2013 at 12:40:26 UTC, Bosak wrote:
 In C# there is this using construct:

just declare variable as scope, and ti will be destructed as son as function exits. void foo () { scope obj = new Object; } // obj will be destructed here you can also use it together with anonymous scope (same as c#) more generally, there is a "scope" statement http://dlang.org/exception-safe.html that can be used where normally try/finally (without catch) would be used, to achieve cleaner code.

Oh yes, I completely forgot about scope.
Aug 05 2013
prev sibling next sibling parent "Bosak" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:
 Michal Minich:

 void foo ()
 {
   scope obj = new Object;
 } // obj will be destructed here

That usage of scope has being deprecated... For Walter: I suggest dmd to give a deprecation message where you use one of the many deprecated D features, like scope classes, floating point comparison operators, and so on. Otherwise D programmers will use those featueres in their code today, and when those feature become deprecated, those people will become angry because of too much code to modify/fix. Bye, bearophile

Interesting. I didn't knew that it is being deprecated. So my suggestion could actually be a good replacement of scope.?
Aug 05 2013
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 5 August 2013 at 12:40:26 UTC, Bosak wrote:
 with(Bitmap image = open("filename.bmp")) {

I think this shoudl be allowed simply for consistency with this: if(auto a = getfoo()) { use a }
Aug 05 2013
next sibling parent Gambler <fake feather.org.ru> writes:
On 8/5/2013 11:30 AM, Bosak wrote:
 On Monday, 5 August 2013 at 13:54:38 UTC, Adam D. Ruppe wrote:
 On Monday, 5 August 2013 at 13:42:01 UTC, Michal Minich wrote:
 But what Bosak proposes is that when "with" statements ends, the
 object should be destructed

That would happen if the object is a struct, or wrapped in a struct, since it would go out of scope at the end of the with and call its destructor then. So then you could just go import std.typecons; with(auto a = Scoped!T()) { ... } and the Scoped destructor does the deleting.

Exactly. My idea is to add third use case of with. Not there are 2 ways to use with(of witch I know): 1) Declare something and use with to not repeat yourself: auto foo = new Foo; with(foo) { name = "bar"; //foo.name = "bar"; } In this case it is only used for object construction and setup. And the with statement doesn't destruct the object or anything like that. 2) Used with types struct Foo { static int bar = 2; } with(Foo) { bar++; //Foo.bar++; } Again with doesn't destruct or anything All of the above are currently available, but I want a third case to be added: 3) Used when you declare something in the with statement with scope only in the with statement with(Foo foo = new Foo) { name = "bar"; } After that foo's destructor gets called and since foo was in the scope of with it goes out of scope and no references are made to foo. There should be a constraint that you cannot take the address of foo in the with statement(i.e assign a global to foo) 3.1) Or used with rvalues?? int[] values; with(new Foo) { name = "bar"; values = getData(); //foo.getData() } //use values taken from foo I think that in case 3.1 it is very intuitive for using resources like files. Instead of writing something like: string text; auto file = open("myfile.txt", "r"); text = t.readlines(); file.close(); You can write this: string text; with(open("myfile.txt", "r")) { //no need to declare variable text = readlines(); //just use the file to get the data }//with automaticaly calls close() on the file, even if exception got thrown And if the exception got thrown in the declaration of the with block, then the with block doesn't execute. For example in the above code if the file didn't exist, an exception would be thrown from open and no variable would be created. I hope that I have made my suggestion more clear.

IMO, using statements in C# are annoying. They make otherwise linear code much harder to read. The *idea* behind them makes total sense, but I dislike the implementation. Instead of writing this: public string[] GetLines(string name) { string result; using (var file = new File(name)) { result = file.ReadText(); } return result.split('\n'); } ...I would very much like to write this: public string[] GetLines(string name) { autodispose var file = new File(name1); string result = file.ReadText(); //file disposed after this line, since it's the last place it's used return result.split('\n'); } Another problem with C#'s using (){} is that it doesn't easily scale from single-method use to object-wide use. For example, would you want to add "using" statements to every single method in a controller just because all of them use the same database object?
Aug 05 2013
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2013-08-05 17:45:23 +0000, Bosak said:
 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.

In http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Three-Unlikely-Succ ssful-Features-of-D I make the argument that C#'s "using" misses the point and D's "scope" statement is a better proposition. Andrei
Aug 05 2013
prev sibling next sibling parent "Michal Minich" <michal.minich gmail.com> writes:
On Monday, 5 August 2013 at 13:33:28 UTC, Adam D. Ruppe wrote:
 On Monday, 5 August 2013 at 12:40:26 UTC, Bosak wrote:
 with(Bitmap image = open("filename.bmp")) {

I think this shoudl be allowed simply for consistency with this: if(auto a = getfoo()) { use a }

This is good. I think it should too. But what Bosak proposes is that when "with" statements ends, the object should be destructed, which is large violation what with statements if for. Not mentioning breaking all the existing code...
Aug 05 2013
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 5 August 2013 at 13:42:01 UTC, Michal Minich wrote:
 But what Bosak proposes is that when "with" statements ends, 
 the object should be destructed

That would happen if the object is a struct, or wrapped in a struct, since it would go out of scope at the end of the with and call its destructor then. So then you could just go import std.typecons; with(auto a = Scoped!T()) { ... } and the Scoped destructor does the deleting.
Aug 05 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 13:25:43 UTC, John Colvin wrote:
 It's not a feature I've ever had the need for so far, but what 
 is the replacement for scope?

http://dlang.org/phobos/std_typecons.html#.scoped
Aug 05 2013
prev sibling next sibling parent "Bosak" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 13:54:38 UTC, Adam D. Ruppe wrote:
 On Monday, 5 August 2013 at 13:42:01 UTC, Michal Minich wrote:
 But what Bosak proposes is that when "with" statements ends, 
 the object should be destructed

That would happen if the object is a struct, or wrapped in a struct, since it would go out of scope at the end of the with and call its destructor then. So then you could just go import std.typecons; with(auto a = Scoped!T()) { ... } and the Scoped destructor does the deleting.

Exactly. My idea is to add third use case of with. Not there are 2 ways to use with(of witch I know): 1) Declare something and use with to not repeat yourself: auto foo = new Foo; with(foo) { name = "bar"; //foo.name = "bar"; } In this case it is only used for object construction and setup. And the with statement doesn't destruct the object or anything like that. 2) Used with types struct Foo { static int bar = 2; } with(Foo) { bar++; //Foo.bar++; } Again with doesn't destruct or anything All of the above are currently available, but I want a third case to be added: 3) Used when you declare something in the with statement with scope only in the with statement with(Foo foo = new Foo) { name = "bar"; } After that foo's destructor gets called and since foo was in the scope of with it goes out of scope and no references are made to foo. There should be a constraint that you cannot take the address of foo in the with statement(i.e assign a global to foo) 3.1) Or used with rvalues?? int[] values; with(new Foo) { name = "bar"; values = getData(); //foo.getData() } //use values taken from foo I think that in case 3.1 it is very intuitive for using resources like files. Instead of writing something like: string text; auto file = open("myfile.txt", "r"); text = t.readlines(); file.close(); You can write this: string text; with(open("myfile.txt", "r")) { //no need to declare variable text = readlines(); //just use the file to get the data }//with automaticaly calls close() on the file, even if exception got thrown And if the exception got thrown in the declaration of the with block, then the with block doesn't execute. For example in the above code if the file didn't exist, an exception would be thrown from open and no variable would be created. I hope that I have made my suggestion more clear.
Aug 05 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
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.
Aug 05 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 5 August 2013 at 14:00:47 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 13:25:43 UTC, John Colvin wrote:
 It's not a feature I've ever had the need for so far, but what 
 is the replacement for scope?

http://dlang.org/phobos/std_typecons.html#.scoped

cool, thanks. Any particular catches a user should be aware of? Other than leaking a reference of course.
Aug 05 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 15:55:00 UTC, John Colvin wrote:
 On Monday, 5 August 2013 at 14:00:47 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 13:25:43 UTC, John Colvin wrote:
 It's not a feature I've ever had the need for so far, but 
 what is the replacement for scope?

http://dlang.org/phobos/std_typecons.html#.scoped

cool, thanks. Any particular catches a user should be aware of? Other than leaking a reference of course.

Quality of implementation of course :) I have not used it much personally and don't know how good it is, but it creates wrapper struct and there can be issues with forwarding methods/operators to wrapped class for some weird corner cases.
Aug 05 2013
prev sibling next sibling parent "Bosak" <bosak gmail.com> writes:
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.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
--snip--

 Bosak:

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

     void opDispose() {
         writeln("Resource disposed!");

You should avoid doing IO in a destructor/finaliser. Writing to STDOUT can fail which may lead to resource leaks (if it throws).
         //in opDispose the resource should dispose all it's 
 resources too
         foreach(res; used)
             res.opDispose();
     }

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

--snip--
Aug 05 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 17:45:25 UTC, Bosak wrote:
 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();
 }

It _is_ similar but not exact match. 2 key differences: 1) destroy works on variety of types, not only classes 2) it puts the object into some invalid state But you can still use class destructor instead of `dispose()` method. But destroy() is considered a power tool that should be used only when absolutely needed. The very necessity to deterministically call some method opposes the concept of garbage collection - it is a sign of bad design and clear indicator that one should do a proper RAII here. I really think D approach here is much cleaner than C# one.
Aug 05 2013
prev sibling next sibling parent "Bosak" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 18:29:09 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 17:45:25 UTC, Bosak wrote:
 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();
 }

It _is_ similar but not exact match. 2 key differences: 1) destroy works on variety of types, not only classes 2) it puts the object into some invalid state But you can still use class destructor instead of `dispose()` method. But destroy() is considered a power tool that should be used only when absolutely needed. The very necessity to deterministically call some method opposes the concept of garbage collection - it is a sign of bad design and clear indicator that one should do a proper RAII here. I really think D approach here is much cleaner than C# one.

Well I don't know much stuff about GC and internals and if you think it is not a good design concept, ok I'm fine with it. I don't "miss" C#'s using statement or IDisposable. I was just giving a suggestion that would be discussed and considered with the community. At least this with(declaration) syntax might make it into the language. And probably use the more "strange" one, where you only give it an rvalue: with(new Foo) { name = "Foo"; //same as temp.name calc(); //same as temp.calc() writeln(); //and even maybe this to be translated to temp.writeln() and then to writeln(temp) ? } Well that was everything I had to say about with, using, and dispose. I'm glad that there was a discussion going.
Aug 05 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-08-05 14:40, Bosak wrote:
 In C# there is this using construct:

 using(Bitmap image = this.OpenImage("filename.bmp")) {
      image.Name = "foo";
      //use image like image.sth
 }

 which is translated to:

 {
      Bitmap image = this.OpenImage("filename.bmp");
      try {
          image.Name = "foo";
          //use image like image.sth
      }
      finally {
          IDisposable obj = image as IDisposable;
          if(obj != null)
              obj.Dispose();
      }
 }

 I know that the with statement is different, but it can be improved so
 that you can declare things in it like an using statement:

 with(Bitmap image = open("filename.bmp")) {
      name = "foo";
      //no need to specify image.sth
 }

 or even a more implicit one:
 with(open("filename.bmp")) {
 //ditto
 }

 And both of the above to be translated to:

 {
      Bitmap temp = expression;
      //use bitmap
      delete temp; // Call destructor/finallizer of the object
      //I'm not sure if delete was the proper way to call a destructor in D
 }

 And I hope you got the point. Tell me what you think.

You can replicate the C# using statement with a library function: module test; import std.stdio; alias writeln println; template isDisposable (T) { enum isDisposable = __traits(compiles, { T t; t.dispose(); }); } void using (alias block, T)(T t) if (isDisposable!(T)) { block(t); scope (exit) t.dispose(); } void using (string block, T)(T t) if (isDisposable!(T)) { with (t) mixin(block); scope (exit) t.dispose(); } class Foo { void bar () { writeln("bar"); } void dispose () { writeln("dispose"); } } void main () { using!(foo => foo.bar())(new Foo); using!q{ bar(); }(new Foo); } If D could have a better syntax for delegates/blocks, it could look like this: using(new Foo ; foo) { foo.bar(); } -- /Jacob Carlborg
Aug 06 2013