digitalmars.D - With statement become like C#'s using?
- Bosak (38/38) Aug 05 2013 In C# there is this using construct:
- Michal Minich (12/13) Aug 05 2013 just declare variable as scope, and ti will be destructed as son
- bearophile (10/14) Aug 05 2013 That usage of scope has being deprecated...
- Michal Minich (4/10) Aug 05 2013 Why it is deprecated? I follow newsgroups, but that I miss...
- John Colvin (3/17) Aug 05 2013 It's not a feature I've ever had the need for so far, but what is
- Dicebot (2/4) Aug 05 2013 http://dlang.org/phobos/std_typecons.html#.scoped
- John Colvin (3/7) Aug 05 2013 cool, thanks. Any particular catches a user should be aware of?
- Dicebot (5/13) Aug 05 2013 Quality of implementation of course :) I have not used it much
- Bosak (3/17) Aug 05 2013 Interesting. I didn't knew that it is being deprecated. So my
- Bosak (2/15) Aug 05 2013 Oh yes, I completely forgot about scope.
- Adam D. Ruppe (3/4) Aug 05 2013 I think this shoudl be allowed simply for consistency with this:
- Michal Minich (6/10) Aug 05 2013 This is good. I think it should too.
- Adam D. Ruppe (8/10) Aug 05 2013 That would happen if the object is a struct, or wrapped in a
- Bosak (54/64) Aug 05 2013 Exactly. My idea is to add third use case of with. Not there are
- Dicebot (8/9) Aug 05 2013 What you propose is rather unwelcome for classes (destruction of
- Bosak (90/100) Aug 05 2013 Oh yes using scoped to achieve that is a good solution. So if I
- Andre Artus (4/19) Aug 05 2013 You should avoid doing IO in a destructor/finaliser. Writing to
- Dicebot (12/17) Aug 05 2013 It _is_ similar but not exact match. 2 key differences:
- Bosak (17/34) Aug 05 2013 Well I don't know much stuff about GC and internals and if you
- Andrei Alexandrescu (6/15) Aug 05 2013 In
- Gambler (25/98) Aug 05 2013 IMO, using statements in C# are annoying. They make otherwise linear
- Jacob Carlborg (45/81) Aug 06 2013 You can replicate the C# using statement with a library function:
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
On Monday, 5 August 2013 at 12:40:26 UTC, Bosak wrote: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 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
Michal Minich:void foo () { scope obj = new Object; } // obj will be destructed hereThat 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
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:Michal Minich:Why it is deprecated? I follow newsgroups, but that I miss... I like it use together with scope classes: scope class C {} - are they too deprecated?void foo () { scope obj = new Object; } // obj will be destructed hereThat usage of scope has being deprecated...
Aug 05 2013
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:Michal Minich:It's not a feature I've ever had the need for so far, but what is the replacement for scope?void foo () { scope obj = new Object; } // obj will be destructed hereThat 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
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?
Aug 05 2013
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:cool, thanks. Any particular catches a user should be aware of? Other than leaking a reference of course.It's not a feature I've ever had the need for so far, but what is the replacement for scope?
Aug 05 2013
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: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.On Monday, 5 August 2013 at 13:25:43 UTC, John Colvin wrote:cool, thanks. Any particular catches a user should be aware of? Other than leaking a reference of course.It's not a feature I've ever had the need for so far, but what is the replacement for scope?
Aug 05 2013
On Monday, 5 August 2013 at 13:11:44 UTC, bearophile wrote:Michal Minich:Interesting. I didn't knew that it is being deprecated. So my suggestion could actually be a good replacement of scope.?void foo () { scope obj = new Object; } // obj will be destructed hereThat 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
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:Oh yes, I completely forgot about scope.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 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
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
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: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...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
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 destructedThat 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
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: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.But what Bosak proposes is that when "with" statements ends, the object should be destructedThat 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
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 behavior via `scoped`. That will improve language consistency.
Aug 05 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: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 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 "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....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 consistency.
Aug 05 2013
--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
On Monday, 5 August 2013 at 17:45:25 UTC, Bosak wrote: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
Aug 05 2013
On Monday, 5 August 2013 at 18:29:09 UTC, Dicebot wrote:On Monday, 5 August 2013 at 17:45:25 UTC, Bosak wrote: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 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.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
Aug 05 2013
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 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 statement is a better proposition. Andrei
Aug 05 2013
On 8/5/2013 11:30 AM, Bosak wrote:On Monday, 5 August 2013 at 13:54:38 UTC, Adam D. Ruppe wrote: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'); } 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?On Monday, 5 August 2013 at 13:42:01 UTC, Michal Minich wrote: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.But what Bosak proposes is that when "with" statements ends, the object should be destructedThat 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
On 2013-08-05 14:40, Bosak wrote: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.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