August 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?

http://dlang.org/phobos/std_typecons.html#.scoped
August 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:
>> 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.
August 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 declarations. It perfectly matches `if` and allows to emulate C# behavior via `scoped`. That will improve language consistency.
August 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:
>> 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.
August 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:
>> 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.
August 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:
>> ...
>
> 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.
August 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--
August 05, 2013
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.
August 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:
>> 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.
August 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:
>> 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?