Thread overview | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 04, 2005 std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
First: In current implementation of MmFile (std.mmfile.d) constructor of MmFile throws exceptions if file cannot be opened. I don't think that throwing exceptions in cunstructors is a good idea at all. MmFile, I think, shall have not public constructors. Instead it should have one static method: static MmFile open(pathname, openmode) {...} which does not throw any errors and returns just null if operation cannot be completed. Having implemented MmFile this way user of it will always get valid MmFile object in valid state. This is more deterministic approach I guess. Phylosophically speaking, negative response on any file open operation is not an exception but rather expected situation. So don't need an exception here. IMHO of course. -------------------------------------------------------- Second: These two methods of MmFile are in conflict by their return values. void[] opSlice(size_t i1, size_t i2) ubyte opIndex(size_t i) (And yet I still didn't get an idea what void[] means - vector of nothings? ) Probably it is better to change it to ubyte[] opSlice(size_t i1, size_t i2) for the sake of simplicity? Andrew. http://terrainformatica.com |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:d2s9kn$460$1@digitaldaemon.com... > First: > > In current implementation of MmFile (std.mmfile.d) > constructor of MmFile throws exceptions if file cannot be opened. Note std.stream also throws when you try to construct a File or BufferedFile and it fails to open or create. Java and .Net also throw. > I don't think that throwing exceptions in cunstructors is a good idea at all. I suppose it is nasty if one is subclassing and trying to practice RAII. Is that what you had in mind? Maybe we should just make sure these things are final classes and cut the problems off from the start. > MmFile, I think, shall have not public constructors. Instead it should have one static method: > > static MmFile open(pathname, openmode) {...} > > which does not throw any errors and returns just null if operation cannot be completed. That isn't too bad, I suppose. Checking for a special return value is a common way to avoid throwing. If anyone tries to use the resulting MmFile on failure they'll get a seg-v, which might be less obvious what happened than an exception thrown from MmFile. > Having implemented MmFile this way user of it will always > get valid MmFile object in valid state. This is more deterministic > approach I guess. How does throwing return an object in an invalid state? It seems just as deterministic to me. > Phylosophically speaking, negative response on > any file open operation is not an exception but > rather expected situation. > So don't need an exception here. IMHO of course. Maybe we need "open" and "open_plz" where open_plz is less ... assertive. :-) > -------------------------------------------------------- > Second: > > These two methods of MmFile are in conflict by their return values. > > void[] opSlice(size_t i1, size_t i2) > ubyte opIndex(size_t i) > > (And yet I still didn't get an idea what void[] means > - vector of nothings? ) > > Probably it is better to change it to > ubyte[] opSlice(size_t i1, size_t i2) for the sake of simplicity? Seems like a good idea to me. |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | On Mon, 4 Apr 2005 13:55:52 -0700, Andrew Fedoniouk <news@terrainformatica.com> wrote:
> These two methods of MmFile are in conflict by their return values.
>
> void[] opSlice(size_t i1, size_t i2)
> ubyte opIndex(size_t i)
>
> (And yet I still didn't get an idea what void[] means
> - vector of nothings? )
My impression is that given that void[] is implicitly castable to any other array type, void[] means "vector of anythings".
Regan
|
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Below: >> In current implementation of MmFile (std.mmfile.d) >> constructor of MmFile throws exceptions if file cannot be opened. > > Note std.stream also throws when you try to construct a File or BufferedFile and it fails to open or create. Java and .Net also throw. And it is bad (IMHO). What happens with this allocated and not constructed object? It just becomes "joy of garbage colector" which acceptable in pure GC based sytems ... But use cases of D are not always "GCable". > >> I don't think that throwing exceptions in cunstructors is a good idea at all. > > I suppose it is nasty if one is subclassing and trying to practice RAII. Is that what you had in mind? Maybe we should just make sure these things are final classes and cut the problems off from the start. Probably I am too deep in C++ where exceptions in constructors are "persons non grata" and, apropos, bad design. But anyway it is better to have valid object or nothing then nobody knows what. > >> MmFile, I think, shall have not public constructors. Instead it should have one static method: >> >> static MmFile open(pathname, openmode) {...} >> >> which does not throw any errors and returns just null if operation cannot be completed. > > That isn't too bad, I suppose. Checking for a special return value is a common way to avoid throwing. If anyone tries to use the resulting MmFile on failure they'll get a seg-v, which might be less obvious what happened than an exception thrown from MmFile. Semantic of 'open' operation always assumes negative results too: (as access to any other system/external resource) Example: Image loadImage(....) { MmFile f = MmFile.open(....); if( f is null ) return null; .... ---versus current ------------------ Image loadImage(....) { MmFile f = null; try { f = new MmFile(....); } catch( FileException ) { } if( f is null ) return null; ..... > >> Having implemented MmFile this way user of it will always >> get valid MmFile object in valid state. This is more deterministic >> approach I guess. > > How does throwing return an object in an invalid state? It seems just as deterministic to me. System first allocates chunk of memory. If exception happens then this memory is just non-determenistic garbage :) > >> Phylosophically speaking, negative response on >> any file open operation is not an exception but >> rather expected situation. >> So don't need an exception here. IMHO of course. > > Maybe we need "open" and "open_plz" where open_plz is less ... assertive. :-) :-))) Program in INTERCAL programming language: DO (5) NEXT (5) DO FORGET #1 PLEASE WRITE IN :1 DO .1 <- 'V":1~'#32768$#0'"$#1'~#3 DO (1) NEXT DO :1 <- "'V":1~'#65535$#0'"$#65535' ~'#0$#65535'"$"'V":1~'#0$#65535'" $#65535'~'#0$#65535'" DO :2 <- #1 PLEASE DO (4) NEXT (4) DO FORGET #1 DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535 $#0'"'~'#0$#65535'"$"'V":1~'#0 $#65535'"$":2~'#65535$#0'"'~'#0$#65535'" DO (1) NEXT DO :2 <- ":2~'#0$#65535'" $"'":2~'#65535$#0'"$#0'~'#32767$#1'" DO (4) NEXT (2) DO RESUME .1 (1) PLEASE DO (2) NEXT PLEASE FORGET #1 DO READ OUT :1 PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3 DO (3) NEXT PLEASE DO (5) NEXT (3) DO (2) NEXT PLEASE GIVE UP -------------------------- Last statement especially .... touching I would say. |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | >> These two methods of MmFile are in conflict by their return values. >> >> void[] opSlice(size_t i1, size_t i2) >> ubyte opIndex(size_t i) >> >> (And yet I still didn't get an idea what void[] means >> - vector of nothings? ) > > My impression is that given that void[] is implicitly castable to any other array type, void[] means "vector of anythings". > void is not anything. It is just nothing. http://dictionary.reference.com/search?q=void See: static void[12] voids; What is voids.sizeof ? |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | > Probably I am too deep in C++ where exceptions in constructors are "persons non grata" and, apropos, bad design.
Really? Since when?
Please offer some sources to substantiate this opinion.
|
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | On Mon, 4 Apr 2005 22:39:24 -0700, Andrew Fedoniouk <news@terrainformatica.com> wrote: >>> These two methods of MmFile are in conflict by their return values. >>> >>> void[] opSlice(size_t i1, size_t i2) >>> ubyte opIndex(size_t i) >>> >>> (And yet I still didn't get an idea what void[] means >>> - vector of nothings? ) >> >> My impression is that given that void[] is implicitly castable to any >> other array type, void[] means "vector of anythings". >> > > void is not anything. It is just nothing. > http://dictionary.reference.com/search?q=void Not in D, IMO. Plus, consider "void *" how can it be a "pointer to nothing", it's actually a "pointer to anything" even in C/C++. Perhaps "void" was a bad choice of word. > See: > static void[12] voids; > > What is voids.sizeof ? 1 Set that way to allow void[] to work. And to allow any type to implicitly cast to void. eg. void foo(void[] a) {} void bar(byte[] a) {} void main() { char[] ca; uint[] ia; long[] la; foo(ca); //ok foo(ia); //ok foo(la); //ok bar(ca); //error bar(ia); //error bar(la); //error } It can be quite useful. Regan |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:d2t7qo$12m7$1@digitaldaemon.com... > Below: > >>> In current implementation of MmFile (std.mmfile.d) >>> constructor of MmFile throws exceptions if file cannot be opened. >> >> Note std.stream also throws when you try to construct a File or BufferedFile and it fails to open or create. Java and .Net also throw. > > And it is bad (IMHO). > What happens with this allocated and not constructed object? > It just becomes "joy of garbage colector" which acceptable in > pure GC based sytems ... But use cases of D are not always "GCable". If one is running D code without a GC they have more things in Phobos to worry about than a leak from an exception. Several parts of the library would have to change APIs to adjust. It would probably be easier to not use phobos at all and start a GC-less API elsewhere. >>> I don't think that throwing exceptions in cunstructors is a good idea at all. >> >> I suppose it is nasty if one is subclassing and trying to practice RAII. Is that what you had in mind? Maybe we should just make sure these things are final classes and cut the problems off from the start. > > Probably I am too deep in C++ where exceptions in constructors > are "persons non grata" and, apropos, bad design. But anyway it is better > to have > valid object or nothing then nobody knows what. > >> >>> MmFile, I think, shall have not public constructors. Instead it should have one static method: >>> >>> static MmFile open(pathname, openmode) {...} >>> >>> which does not throw any errors and returns just null if operation cannot be completed. >> >> That isn't too bad, I suppose. Checking for a special return value is a common way to avoid throwing. If anyone tries to use the resulting MmFile on failure they'll get a seg-v, which might be less obvious what happened than an exception thrown from MmFile. > > Semantic of 'open' operation always assumes negative results too: (as access to any other system/external resource) Some things are more likely to fail than others. When calling new to allocate a new object fails it does not return null - it throws. That makes sense since running out of memory is exceptional. Opening a socket accross a flaky network is more likely to fail so I could see the usefullness in returning null or some special failure flag. > Example: > > Image loadImage(....) { > MmFile f = MmFile.open(....); > if( f is null ) return null; > .... > ---versus current ------------------ > > Image loadImage(....) { > MmFile f = null; > try { f = new MmFile(....); } > catch( FileException ) { } > if( f is null ) return null; > ..... Yes, and then the loadImage has to check for null etc etc. Exceptions are a way of ensuring that "everyone checks for null" and it makes sure the exception happens at the point of opening the file instead of five routines later when someone tries to access a null reference. If you are concerned about the amount of code required to write a try/catch then you can improve on your version slightly by putting the return in the catch - though again I tend to think allowing the exception to go through loadImage is the right thing to do. Or if we could chain exceptions (see my earlier thread about chaining exceptions) one could write Image loadImage(....) { MmFile f = null; try { f = new MmFile(....); } catch( FileException e) { throw new ImageException("Failed to load",e); } ..... >> >>> Having implemented MmFile this way user of it will always >>> get valid MmFile object in valid state. This is more deterministic >>> approach I guess. >> >> How does throwing return an object in an invalid state? It seems just as deterministic to me. > > System first allocates chunk of memory. > If exception happens then this memory is just > non-determenistic garbage :) Free your mind, not your memory :-) Don't worry about a block or two that become garbage from an exception - it won't happen often enough to be measurable. >>> Phylosophically speaking, negative response on >>> any file open operation is not an exception but >>> rather expected situation. >>> So don't need an exception here. IMHO of course. >> >> Maybe we need "open" and "open_plz" where open_plz is less ... assertive. :-) > > :-))) > > Program in INTERCAL programming language: > > DO (5) NEXT > (5) DO FORGET #1 > PLEASE WRITE IN :1 > DO .1 <- 'V":1~'#32768$#0'"$#1'~#3 > DO (1) NEXT > DO :1 <- "'V":1~'#65535$#0'"$#65535' > ~'#0$#65535'"$"'V":1~'#0$#65535'" > $#65535'~'#0$#65535'" > DO :2 <- #1 > PLEASE DO (4) NEXT > (4) DO FORGET #1 > DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535 > $#0'"'~'#0$#65535'"$"'V":1~'#0 > $#65535'"$":2~'#65535$#0'"'~'#0$#65535'" > DO (1) NEXT > DO :2 <- ":2~'#0$#65535'" > $"'":2~'#65535$#0'"$#0'~'#32767$#1'" > DO (4) NEXT > (2) DO RESUME .1 > (1) PLEASE DO (2) NEXT > PLEASE FORGET #1 > DO READ OUT :1 > PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3 > DO (3) NEXT > PLEASE DO (5) NEXT > (3) DO (2) NEXT > PLEASE GIVE UP > -------------------------- > Last statement especially .... touching I would say. Nice. It's like getting a "System panic" message on a Sun box. If the system is panicing, then what should I be doing? yikes. |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrew Fedoniouk | Andrew Fedoniouk wrote: <snip> > MmFile, I think, shall have not public constructors. Instead > it should have one static method: > > static MmFile open(pathname, openmode) {...} > > which does not throw any errors and returns just null if operation > cannot be completed. <snip> No. What would be the point of having exceptions if we're going to go out of way not to use them? http://www.digitalmars.com/d/errors.html Stewart. -- My e-mail is valid but not my primary mailbox. Please keep replies on the 'group where everyone may benefit. |
April 05, 2005 Re: std.mmfile.d observations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew | >> Probably I am too deep in C++ where exceptions in constructors are "persons non grata" and, apropos, bad design. > > Really? Since when? > > Please offer some sources to substantiate this opinion. > Sorry, Matthew, I've propagated problem with exceptions in destructors [1] onto constructors also. Mea culpa. BTW: MmFile destructor is also generating exceptions. In any case general rule: "you should avoid unnecessary try blocks" [2] sounds reasonable as a general recommendation. IMHO, System resource wrappers should not throw exceptions or at least should allow non exceptional forms of operations. There are too many practical reasons for that. One possible implemetataion: class MmFile { this() {} // constructs empty wrapper, no exceptions this(pathname) { if( !open(pathname) ) throw FileException(...). } // the only way to report problem in ctor is to throw an exception. bool open( pathname) // tries to open physical object, no exception here. bool close( ) // tries to 'close' physical object, no exception here. ~this() { close(); } // no exception here, ignorabimus et ignoramus } But I am personally prefer the form : class MmFile { potected this() {} // protected, not constructable in 'void' state externally static MmFile open( pathname); // factory alike ctor. // tries to open physical object, no exception here. // returns null if MmFile could not be open in requested state. bool close( ) // tries to 'close' physical object, no exception here. ~this() { close(); } // no exception here } The second form does not even try to allocate any object if it cannot be created. If I (consumer of MmFile) need an exception I can always throw them after failed open. I would like to have an option to manage throw or not to throw problem by myself. Andrew Fedoniouk. http://terrainformatica.com Literature: [1] Scott Meyer, More Effective C++. "Item 11: Prevent exceptions from leaving destructors." ( http://www.ishiboo.com/~nirva/c++/eff/MEC/MI11_FR.HTM ) [2] Scott Meyer, More Effective C++. "Item 15: Understand the costs of exception handling" |
Copyright © 1999-2021 by the D Language Foundation