October 06, 2015
On Tuesday, 6 October 2015 at 06:45:47 UTC, Jonathan M Davis wrote:
> On Monday, 5 October 2015 at 23:08:37 UTC, bitwise wrote:
>> Well, again that has it's pros and cons. This is why I just want a normal language solution like DIP74.
>
> They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.
>
> - Jonathan M Davis


On Monday, 5 October 2015 at 18:18:15 UTC, bitwise wrote:
> The deterministic destruction is actually what I'm after.

For my purposes, they are pretty much the same.

So again, I'll paste the same example:

class Texture { }
class Texture2D : Texture {
    this() { /* load texture... */ }
    ~this { /* free texture */ }     // OOPS, when, if ever, will this be called?
}

Memory is not only thing that has to be cleaned up.

    Bit

October 06, 2015
On Tuesday, 6 October 2015 at 17:03:07 UTC, bitwise wrote:
> On Tuesday, 6 October 2015 at 06:45:47 UTC, Jonathan M Davis wrote:
>> They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.

> For my purposes, they are pretty much the same.
>
> So again, I'll paste the same example:
>
> class Texture { }
> class Texture2D : Texture {
>     this() { /* load texture... */ }
>     ~this { /* free texture */ }     // OOPS, when, if ever, will this be called?
> }
>
> Memory is not only thing that has to be cleaned up.

Well, they might seem the same when you only look at that part, but they won't both solve your problem, depending on what you're trying to do.

But in general, at this point, with D, if you want deterministic destruction, then you use structs. Classes are not the appropriate place for it. If they were ref-counted, then they could be, but as long as they're not, then classes are not the place to have stuff that cares about deterministic destruction. And if you're stuck with stuff in classes that do care about deterministic destruction, then you have to use the sort of solutions that C# and Java use where you don't rely on the destructor/finalizer to clean anything up except for the cases where you screw up and forget to manually call the function that does the cleanup.

I expect that we'll get ref-counting for classes at some point, since while ref-counting with structs works, as I understand it, it does have some holes that make it less than ideal (but not necessarily unusable). And for some reason, IIRC, RefCounted doesn't work with classes, so you'd be forced to write your own ref-counted wrapper. It can certainly be done though.

- Jonathan M Davis
October 06, 2015
On Tuesday, 6 October 2015 at 17:20:39 UTC, Jonathan M Davis wrote:
> On Tuesday, 6 October 2015 at 17:03:07 UTC, bitwise wrote:
>> On Tuesday, 6 October 2015 at 06:45:47 UTC, Jonathan M Davis wrote:
>>> They're not the same thing at all. scoped is supposed to put the class on the stack, not the heap. And it's not ref-counted. It's so that you can create a class object in place, use it, and throw it away without doing any heap allocation. Essentially, it allows you to use a class as if it were a non-copyable struct. Even if we end up with ref-counting supported in the language, it doesn't obviate the need for scoped classes. They're for different use cases.
>
>> For my purposes, they are pretty much the same.
>>
>> So again, I'll paste the same example:
>>
>> class Texture { }
>> class Texture2D : Texture {
>>     this() { /* load texture... */ }
>>     ~this { /* free texture */ }     // OOPS, when, if ever, will this be called?
>> }
>>
>> Memory is not only thing that has to be cleaned up.
>
> Well, they might seem the same when you only look at that part, but they won't both solve your problem, depending on what you're trying to do.
>
> But in general, at this point, with D, if you want deterministic destruction, then you use structs. Classes are not the appropriate place for it. If they were ref-counted, then they could be, but as long as they're not, then classes are not the place to have stuff that cares about deterministic destruction. And if you're stuck with stuff in classes that do care about deterministic destruction, then you have to use the sort of solutions that C# and Java use where you don't rely on the destructor/finalizer to clean anything up except for the cases where you screw up and forget to manually call the function that does the cleanup.

I'm not sure what else I can say. The example I posted says it all, and it can't be done properly in D (or C#, but why lower the bar because of their mistakes? ;)

I'm not sure exactly how C# and Java handle destruction for non-memory resources, but I'm guessing it's something like calling GC.collect() manually every couple of seconds. If the textures aren't released in the destructor, I don't really see any other way to tell when they're referenced or not.

Of course though, mobile devices are the new PC, and battery life is very much a concern, so this is a total waste...especially if I'm doing very little GC allocation anyways. Also, of course, there are the performance issues.

> I expect that we'll get ref-counting for classes at some point, since while ref-counting with structs works, as I understand it, it does have some holes that make it less than ideal (but not necessarily unusable). And for some reason, IIRC, RefCounted doesn't work with classes, so you'd be forced to write your own ref-counted wrapper. It can certainly be done though.
>
> - Jonathan M Davis

Correct, RefCounted doesn't work with classes. Not sure why, but I wrote my own, and trivial unittests pass:
http://dpaste.dzfl.pl/997615d2d188

But again, as I've already mentioned, it hides the type, has annoying syntax, and most importantly, is error prone. I can't really write a class thats meant to be used with RC(T) and know that no one will ever try to use it on it's own, GC allocated.

D needs a real solution here.
http://imgur.com/v6CIWln

    Bit

October 06, 2015
You don't need RC, just use Unique. In most cases you don't want to use RC, because you never have control over the ownership.
October 06, 2015
On Tuesday, 6 October 2015 at 18:10:42 UTC, bitwise wrote:
> On Tuesday, 6 October 2015 at 17:20:39 UTC, Jonathan M Davis wrote:
> I'm not sure what else I can say. The example I posted says it all, and it can't be done properly in D (or C#, but why lower the bar because of their mistakes? ;)

It's a side effect of having the lifetime of an object managed by the GC. There's no way around that except to use something else like manual memory management or reference counting. In D, it's a good reason to use structs to manage resources like that, and since most objects really have no need of inheritance and have no business being classes, it's usually fine. But in the cases where you do have to use a class, it can get annoying.

> I'm not sure exactly how C# and Java handle destruction for non-memory resources, but I'm guessing it's something like calling GC.collect() manually every couple of seconds. If the textures aren't released in the destructor, I don't really see any other way to tell when they're referenced or not.
>
> Of course though, mobile devices are the new PC, and battery life is very much a concern, so this is a total waste...especially if I'm doing very little GC allocation anyways. Also, of course, there are the performance issues.

You simply do not rely on the GC or the destruction of the object to free system resources. You manually call a function on the object to free those resources when you're done with it. In the case of C#, they have a construct to help with it that (IIRC) is something like

using(myObj)
{
} // myObj.dispose() is called when exiting this scope

In Java, you'd have no choice but to call dispose manually. And yes, that sucks, but it's life with a GC-managed object. The GC has a number of benefits to it, but it does not come without its costs.

Having the option to have properly ref-counted classes in addition to classes managed by the GC would definitely be an improvement, and I expect that we'll get there at some point, but there _are_ ways to deal with the problem in the interim, even if it's not ideal.

In most cases though, just don't use classes. In most cases, inheritance is a horrible way to write programs anyway, because it's _horrible_ for code reuse. It definitely has its uses, but I've found that I rarely need classes in D. I suspect that far too many folks new to D end up using classes instead of structs just because they're used to using classes in C++ or Java or whatever.

- Jonathan M Davis
October 06, 2015
On Tuesday, 6 October 2015 at 18:43:42 UTC, Jonathan M Davis wrote:
> On Tuesday, 6 October 2015 at 18:10:42 UTC, bitwise wrote:
>> [...]
>
> It's a side effect of having the lifetime of an object managed by the GC. There's no way around that except to use something else like manual memory management or reference counting. In D, it's a good reason to use structs to manage resources like that, and since most objects really have no need of inheritance and have no business being classes, it's usually fine. But in the cases where you do have to use a class, it can get annoying.
>
>> [...]
>
> You simply do not rely on the GC or the destruction of the object to free system resources. You manually call a function on the object to free those resources when you're done with it. In the case of C#, they have a construct to help with it that (IIRC) is something like
>
> using(myObj)
> {
> } // myObj.dispose() is called when exiting this scope
>
> In Java, you'd have no choice but to call dispose manually. And yes, that sucks, but it's life with a GC-managed object. The GC has a number of benefits to it, but it does not come without its costs.
>
> Having the option to have properly ref-counted classes in addition to classes managed by the GC would definitely be an improvement, and I expect that we'll get there at some point, but there _are_ ways to deal with the problem in the interim, even if it's not ideal.
>
> In most cases though, just don't use classes. In most cases, inheritance is a horrible way to write programs anyway, because it's _horrible_ for code reuse. It definitely has its uses, but I've found that I rarely need classes in D. I suspect that far too many folks new to D end up using classes instead of structs just because they're used to using classes in C++ or Java or whatever.
>
> - Jonathan M Davis

As of Java 7

    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }


Or just use a functional programming pattern for resource management:

withFile (something, { fd -> work with file })

Better languages allow to write that like

withFile (something) { fd -> work with file }

GC is not an hindrance when the languages are built to properly work with it.

--
Paulo
October 06, 2015
On Tuesday, 6 October 2015 at 19:15:09 UTC, Paulo Pinto wrote:
> GC is not an hindrance when the languages are built to properly work with it.
>
> --
> Paulo

+1, tired of repeating this.

October 06, 2015
On Tuesday, 6 October 2015 at 18:43:42 UTC, Jonathan M Davis wrote:
> In most cases though, just don't use classes. In most cases, inheritance is a horrible way to write programs anyway, because it's _horrible_ for code reuse. It definitely has its uses, but I've found that I rarely need classes in D. I suspect that far too many folks new to D end up using classes instead of structs just because they're used to using classes in C++ or Java or whatever.

What improvements to structs do you think would help people coming from C++/Java most?
October 06, 2015
On Tuesday, 6 October 2015 at 20:04:06 UTC, jmh530 wrote:
> On Tuesday, 6 October 2015 at 18:43:42 UTC, Jonathan M Davis wrote:
>> In most cases though, just don't use classes. In most cases, inheritance is a horrible way to write programs anyway, because it's _horrible_ for code reuse. It definitely has its uses, but I've found that I rarely need classes in D. I suspect that far too many folks new to D end up using classes instead of structs just because they're used to using classes in C++ or Java or whatever.
>
> What improvements to structs do you think would help people coming from C++/Java most?

I don't think the problem is with structs. The problem is that programmers coming from other languages default to using classes. The default in D should always be a struct. You use a class because you actually need inheritance or because you want to ensure that a type is always a reference type and don't want to go to the trouble of writing a struct that way (and even then, you should probably just write the struct that way). You shouldn't use a class as your default for user-defined types in D. But because other languages don't have structs quite like D does, and you use classes in those other languages, that's what most everyone wants to use - at least initially.

It would not surprise me if there are some compiler bugs with regards to structs that result in some loopholes that shouldn't be there (e.g. with @disable-ing stuff), but on the whole, I think that D structs are very well designed as they are. The only real issue IMHO is having an init value vs having a default constructor, and that's a tradeoff with pros and cons on both sides. It does sometimes seem painful to folks coming from C++, but on the whole, I think that we're better off for it.

- Jonathan M Davis
October 06, 2015
On Tuesday, 6 October 2015 at 18:43:42 UTC, Jonathan M Davis wrote:
> On Tuesday, 6 October 2015 at 18:10:42 UTC, bitwise wrote:
>> On Tuesday, 6 October 2015 at 17:20:39 UTC, Jonathan M Davis wrote:
>> I'm not sure what else I can say. The example I posted says it all, and it can't be done properly in D (or C#, but why lower the bar because of their mistakes? ;)
>
> It's a side effect of having the lifetime of an object managed by the GC. There's no way around that except to use something else like manual memory management or reference counting.

You are literally repeating what I just said in different words.

> in D, it's a good reason to use structs to manage resources like that, and since most objects really have no need of inheritance and have no business being classes, it's usually fine.

This is an opinion.

I want polymorphism AND deterministic destruction, and the least you could do is just admit that it's a downside to D not having it, instead of trying to tell me that everything I know is wrong..

> But in the cases where you do have to use a class, it can get annoying.

YES, its does, and it's not just an odd case here and there..

> You simply do not rely on the GC or the destruction of the object to free system resources. You manually call a function on the object to free those resources when you're done with it.

I'm sorry, but I almost can't believe you're saying this.

So, you're saying you want me to just revert back to manual resource management and accept that huge resources like textures and such may just leak if someone doesn't use them right? or throws an exception? in a language like D that is supposed to be safe?

> In the case of C#, they have a construct to help with it that (IIRC) is something like
>
> using(myObj)
> {
> } // myObj.dispose() is called when exiting this scope

For the THIRD time, I'll post my example:

class Texture { }
class Texture2D : Texture {
    this() { /* load texture... */ }
    ~this { /* free texture */ }     // OOPS, when, if ever, will this be called?
}

Now, does this really seem like a realistic use case to you?

using(Texture tex = new Texture2D) {
    // ...
}

> Having the option to have properly ref-counted classes in addition to classes managed by the GC would definitely be an improvement, and I expect that we'll get there at some point, but there _are_ ways to deal with the problem in the interim, even if it's not ideal.

This brings me right back to where I started this, which was asking about this situation.

_Is_ it just the interim? Will DIP74 actually ever be implemented? if so, when?

> In most cases though, just don't use classes. In most cases, inheritance is a horrible way to write programs anyway,

Opinion.

> I suspect that far too many folks new to D end up using classes instead of structs just because they're used to
> using classes in C++ or Java or whatever.

I use classes for polymorphism, and although I can't speak for everyone else, I doubt I'm the only one.

      Bit