Jump to page: 1 2 3
Thread overview
std.mmfile.d observations
Apr 04, 2005
Andrew Fedoniouk
Apr 05, 2005
Ben Hinkle
Apr 05, 2005
Andrew Fedoniouk
Apr 05, 2005
Matthew
Apr 05, 2005
Andrew Fedoniouk
Apr 06, 2005
Matthew
Apr 07, 2005
Andrew Fedoniouk
Apr 07, 2005
Matthew
Apr 05, 2005
Ben Hinkle
Apr 05, 2005
Andrew Fedoniouk
Apr 05, 2005
Ben Hinkle
Apr 05, 2005
brad
Apr 05, 2005
Regan Heath
Apr 05, 2005
brad
Apr 05, 2005
Regan Heath
Apr 05, 2005
Regan Heath
Apr 05, 2005
Andrew Fedoniouk
Apr 05, 2005
Regan Heath
Apr 05, 2005
Andrew Fedoniouk
Apr 05, 2005
Regan Heath
Apr 05, 2005
Andrew Fedoniouk
Apr 06, 2005
Regan Heath
Apr 06, 2005
Georg Wrede
Apr 05, 2005
Stewart Gordon
April 04, 2005
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
"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
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
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
>> 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
> 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
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
"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
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
>> 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"




« First   ‹ Prev
1 2 3