www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - why std.stdio.File is a struct?

reply lumpyzhu <zhuxueling neusoft.com> writes:
std.stdio.File has reference counter inside,
why not std.stdio.File is class?
Oct 19 2016
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Thursday, October 20, 2016 06:59:12 lumpyzhu via Digitalmars-d wrote:
 std.stdio.File has reference counter inside,
 why not std.stdio.File is class?
By using a struct with a reference count, you get deterministic destruction, and the file will be closed as soon as the reference count hits zero. If it were a class, then it would only be closed when the GC happened to collect the memory, and there's no guarantee that it will _ever_ collect the memory (e.g. the GC normally only runs when you call new, so if you never allocate memory again after allocating the File, then the GC will never collect it even if nothing refers to it anymore). User-defined types that manage system resources are pretty much always better off as structs so that they can have deterministic destruction. Java and C# have a terrible time with stuff like closing files, essentially requiring you to do it manually, because there's no guarantee that the finalizers for their file classes will ever run, and you risk the resource never being released until the program terminates, which can be a big problem. We'd have the same problem if we used a class for std.stdio.File, whereas using a struct works great. In general, in D, if you don't need inheritance and polymorphism, you probably shouldn't be using a class. - Jonathan M Davis
Oct 20 2016
next sibling parent Kagamin <spam here.lot> writes:
On Thursday, 20 October 2016 at 07:40:05 UTC, Jonathan M Davis 
wrote:
 User-defined types that manage system resources are pretty much 
 always better off as structs so that they can have 
 deterministic destruction.
They could be reference counted classes if it played well with the language.
 In general, in D, if you don't need inheritance and 
 polymorphism, you probably shouldn't be using a class.
Streams genuinely need polymorphism though because they can present a wide variety of devices.
Oct 20 2016
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Thursday, 20 October 2016 at 07:40:05 UTC, Jonathan M Davis 
wrote:
 In general, in D, if you don't need inheritance and 
 polymorphism, you probably shouldn't be using a class.
and even if you need, most of the time it is better to write templated free functions with constraints instead. ;-)
Oct 20 2016
parent Chris <wendlec tcd.ie> writes:
On Thursday, 20 October 2016 at 12:24:14 UTC, ketmar wrote:
 On Thursday, 20 October 2016 at 07:40:05 UTC, Jonathan M Davis 
 wrote:
 In general, in D, if you don't need inheritance and 
 polymorphism, you probably shouldn't be using a class.
and even if you need, most of the time it is better to write templated free functions with constraints instead. ;-)
I use a few classes, but mainly to structure the program (some are singletons). The rest are all structs and functions/templated functions. On hindsight, I would probably not go down that path again. Better avoid the class system altogether, ask the British ;)
Oct 21 2016
prev sibling parent reply lumpyzhu <zhuxueling neusoft.com> writes:
On Thursday, 20 October 2016 at 07:40:05 UTC, Jonathan M Davis 
wrote:
 On Thursday, October 20, 2016 06:59:12 lumpyzhu via 
 Digitalmars-d wrote:
 std.stdio.File has reference counter inside,
 why not std.stdio.File is class?
By using a struct with a reference count, you get deterministic destruction, and the file will be closed as soon as the reference count hits zero. If it were a class, then it would only be closed when the GC happened to collect the memory, and there's no guarantee that it will _ever_ collect the memory (e.g. the GC normally only runs when you call new, so if you never allocate memory again after allocating the File, then the GC will never collect it even if nothing refers to it anymore). User-defined types that manage system resources are pretty much always better off as structs so that they can have deterministic destruction. Java and C# have a terrible time with stuff like closing files, essentially requiring you to do it manually, because there's no guarantee that the finalizers for their file classes will ever run, and you risk the resource never being released until the program terminates, which can be a big problem. We'd have the same problem if we used a class for std.stdio.File, whereas using a struct works great. In general, in D, if you don't need inheritance and polymorphism, you probably shouldn't be using a class. - Jonathan M Davis
thanks.. but structs are copy by value, In C++, I can use reference to avoid value-copy, ------------------------------------------ class MyClass {....}; void myFunc(const MyClass& a, MyClass& b) {...}; { MyClass object; myFunc(object); // f will destroyed here. } ------------------------------------------ in c++, I know where the object is destroyed.. but how to convert this c++ code to d?
Oct 22 2016
parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sunday, October 23, 2016 06:13:29 lumpyzhu via Digitalmars-d wrote:
 thanks..
 but structs are copy by value,
 In C++, I can use reference to avoid value-copy,

 ------------------------------------------
 class MyClass {....};
 void myFunc(const MyClass& a, MyClass& b) {...};

 {
        MyClass object;
        myFunc(object);
        // f will destroyed here.
 }
 ------------------------------------------
 in c++, I know where the object is destroyed..
 but how to convert this c++ code to d?
You can mark a parameter as ref, and you get something similar to C++'s &, except that it only works on parameters, return types, and the variable for the current element in a foreach loop (you can't declare local variables that are ref), and ref parameters only ever accept lvalues, even if they're const. e.g. void foo(ref int i) {...} ref int bar() { return _i; } foreach(i, ref e; arr) {...} I think that most D code just passes structs around without worrying about the cost of copying unless the struct is particularly large or profiling has shown that copying it is too expensive. For a lot of stuff, it simply isn't a problem. And when it is, there's ref, or the struct can be put on the heap and passed around by pointer. But because we don't have an equivalent for const& that accepts rvalues, using ref simply to avoid copying can get annoying. So, it doesn't make much sense to do it unless it's actually necessary (whereas a lot of C++ code does it just in case it matters). There is talk of possibly adding a way to pass rvalues by ref in D, in which case, you would get something similar to C++ const&, but there are problems caused by C++'s approach that we don't want in D, and D's const is enough more restrictive than C++ const that whatever we do can't be tied to const. - Jonathan M Davis
Oct 22 2016
parent Namespace <rswhite4 gmail.com> writes:
On Sunday, 23 October 2016 at 06:36:21 UTC, Jonathan M Davis 
wrote:
 You can mark a parameter as ref, and you get something similar 
 to C++'s &, except that it only works on parameters, return 
 types, and the variable for the current element in a foreach 
 loop (you can't declare local variables that are ref), and ref 
 parameters only ever accept lvalues, even if they're const. e.g.

 void foo(ref int i) {...}

 ref int bar() { return _i; }

 foreach(i, ref e; arr) {...}

 I think that most D code just passes structs around without 
 worrying about the cost of copying unless the struct is 
 particularly large or profiling has shown that copying it is 
 too expensive. For a lot of stuff, it simply isn't a problem. 
 And when it is, there's ref, or the struct can be put on the 
 heap and passed around by pointer. But because we don't have an 
 equivalent for const& that accepts rvalues, using ref simply to 
 avoid copying can get annoying. So, it doesn't make much sense 
 to do it unless it's actually necessary (whereas a lot of C++ 
 code does it just in case it matters).

 There is talk of possibly adding a way to pass rvalues by ref 
 in D, in which case, you would get something similar to C++ 
 const&, but there are problems caused by C++'s approach that we 
 don't want in D, and D's const is enough more restrictive than 
 C++ const that whatever we do can't be tied to const.

 - Jonathan M Davis
There is still the way to use an universal rvalue => lvalue conversion function.
Oct 23 2016