November 01, 2005
Please don't kill opCall for classes, it makes for great factory method syntax :)  If you're leaning that way, maybe only allow static opCall for abstract classes?


"Walter Bright" <newshound@digitalmars.com> wrote in message news:djodvq$2nvh$3@digitaldaemon.com...
>
> "Vathix" <chris@dprogramming.com> wrote in message news:op.sy8x7py7l2lsvj@esi...
>> I like it. Only problem I can think of is conflicts if the class has a static opCall. Perhaps classes should not have them
>
> I'm hard pressed to see the point of them for classes anyway.
>
>> (but they're very
>> handy for structs/unions). This extra code in the compiler to support it
>> could possibly be hacked in by adding an internal, implicit static opCall
>> to all classes, which are translated to RAII constructors when invoked
>>  from an initializer ;)
>
> There's more work to get all the details ironed out, but that is where I want to go. It's needed because there are a certain class of problems D doesn't work well without.
>
> 


November 01, 2005
"James Dunne" <james.jdunne@gmail.com> wrote in message news:dk5ncl$1hp0$1@digitaldaemon.com...
> That'd get real ugly, real quick.  Especially when you have complex
> lines of code that are using vectors of doubles with operator overloads.
>   Granted, the assert statement could go in the vector's operator
> overloads, but still the problem remains for complex lines of
> floating-point calculations...  Let me fabricate an example from a line
> of my code:
>
> debug {
> assert(!isnan(a));
> assert(!isnan(b));
> assert(!isnan(c));
> assert(!isnan(d));
> assert(!isnan(e));
> assert(!isnan(f));
> }
> T = (a * b + c*d + (a * (e - b) + (e - c) * d) / f) * (1.0 / (a + d));
>
> (the variable names have been changed to protect intellectual property and to disguise any actual meaning of the calculation)

What I'd to is just add: assert(!isnan(T)). Then, only if it trips, would I
worry about which one it is.


> Anyway, this is just one of a few hundred lines of calculations in the model, and requiring that block of 6 assert lines to be called before each line (worst-case scenario of course) is a bit overwhelming.  In reality, you'd only have to check the inputs as they come into the function with a nice contract - but to be honest, I never have used DbC and completely forget that they exist.
>
> The way I see it, there are 2 possible solutions here:
>
> 1) Have compiler throw in assert(!isnan(x)) statements automatically
> under debug build (possibly with additional compiler switch) before each
> floating-point operation

NaN is a useful value in its own right, especially when doing data collection. You don't want to throw out your entire data set because of a few known bad values (such as data from a space probe, or data from a camera with a few stuck pixels). You only want to know if your output is affected by those bad values. NaN fits the bill perfectly. (In digital electronics, one normally deals with True, False, and Don't Know. NaN corresponds to the Don't Know state.) Implementing "nans-are-bugs" would preclude D from being useful for a significant problem space.


> 2) Switch default QNaN initialization to SNaN and check FE_EXCEPT flag after each floating-point operation to throw a FloatingPointException (again under debug build possibly with additional compiler switch)
>
> Are you sure that FE_EXCEPT flag is the only thing that happens when a SNaN is hit?

Yes (actually, it's FE_INVALID). A qnan does not set FE_INVALID.

> Isn't there a hardware interrupt tied in somewhere for
> this sort of thing?  Throwing up a flag is nice and all, but quite
> useless if it must be checked explicitly after each floating-point
> operation...

It's possible to configure the hardware to do that. I don't know if such is supported by Win32 or Linux, though. I'd also caution against it, because all sorts of floating point code will start failing, as that isn't expected behavior.


November 02, 2005
Walter Bright wrote:
> 
> NaN is a useful value in its own right, especially when doing data
> collection. You don't want to throw out your entire data set because of a
> few known bad values (such as data from a space probe, or data from a camera
> with a few stuck pixels). You only want to know if your output is affected
> by those bad values. NaN fits the bill perfectly. (In digital electronics,
> one normally deals with True, False, and Don't Know. NaN corresponds to the
> Don't Know state.) Implementing "nans-are-bugs" would preclude D from being
> useful for a significant problem space.

I agree.  Were this to be implemented it should be purely optional. I've never felt the need for this feature myself, but if it's not too hard to do, perhaps it could be a compile or run-time option?

>>Isn't there a hardware interrupt tied in somewhere for
>>this sort of thing?  Throwing up a flag is nice and all, but quite
>>useless if it must be checked explicitly after each floating-point
>>operation...
> 
> It's possible to configure the hardware to do that. I don't know if such is
> supported by Win32 or Linux, though. I'd also caution against it, because
> all sorts of floating point code will start failing, as that isn't expected
> behavior.

Win32 supports at least some of the FP exceptions through SEH, but divide by zero was the only one I saw listed in the Win32 docs that seemed particularly useful and D already supports that one.  I couldn't say whether Linux supports this, but I imagine it does.


Sean
November 02, 2005
"Sean Kelly" <sean@f4.ca> wrote in message news:dk914a$1afm$1@digitaldaemon.com...
> Walter Bright wrote:
> >
> > NaN is a useful value in its own right, especially when doing data collection. You don't want to throw out your entire data set because of
a
> > few known bad values (such as data from a space probe, or data from a
camera
> > with a few stuck pixels). You only want to know if your output is
affected
> > by those bad values. NaN fits the bill perfectly. (In digital
electronics,
> > one normally deals with True, False, and Don't Know. NaN corresponds to
the
> > Don't Know state.) Implementing "nans-are-bugs" would preclude D from
being
> > useful for a significant problem space.
>
> I agree.  Were this to be implemented it should be purely optional. I've never felt the need for this feature myself, but if it's not too hard to do, perhaps it could be a compile or run-time option?

C and C++ are loaded up with compiler switches that change the meaning of the language. I really want to do my best to avoid this. In the end, it does the users a disservice because they can't rely on consistent semantics.


November 02, 2005
Sean Kelly wrote:
> In article <djodvq$2nvh$3@digitaldaemon.com>, Walter Bright says...
> 
>>There's more work to get all the details ironed out, but that is where I
>>want to go. It's needed because there are a certain class of problems D
>>doesn't work well without.
> 
> I'm glad to hear it :)  This is the only real syntax-level issue I have with D,
> and it's a relief to know that it will be addressed at some point.

Oh, one more question, is there any chance that this will allow static object composition as well?  ie.

class C {}
class D { C c = C(); }

Not a big deal, but it would be nice if the entire class could avoid the use of new rather than just the outer instantiation.  The syntax seems a bit weird for this purpose (as the above doesn't allow for c to be constructed in D's ctor), but perhaps there's a way to clarify it somehow?


Sean
November 02, 2005
Sean Kelly wrote:
> Oh, one more question, is there any chance that this will allow static object composition as well?  ie.
> 
> class C {}
> class D { C c = C(); }
> 
> Not a big deal, but it would be nice if the entire class could avoid the use of new rather than just the outer instantiation.  The syntax seems a bit weird for this purpose (as the above doesn't allow for c to be constructed in D's ctor), but perhaps there's a way to clarify it somehow?

I also think that it would be a good idea to handle static object composition with the same syntax as classes on the stack.  In either case, we are really declaring a class-value variable rather than a class-reference variable.
November 02, 2005
Russ Lewis wrote:
> 
> I also think that it would be a good idea to handle static object composition with the same syntax as classes on the stack.  In either case, we are really declaring a class-value variable rather than a class-reference variable.

Technically, it's a class reference to a stack instance as this change would not provide value semantics for classes.  The distinction is clear when considering this:

class C {}
class D {
    C c;

    this() {
        c = C();
    }

    this( int x ) {
        c = new C();
    }
}

This is completely legal with the proposed semantics and would result in c referring to an invalid location if the default ctor is called. Currently, we can use placement new to fake static composition:

class E {
    C c;

    ubyte[C.sizeof] buf;

    this() {
        c = new (&buf[0]) C();
    }
}

(I'm just guessing at syntax here as I haven't actually tried this)

but this raises alignment issues and such that a language-supported method does not have.


Sean
November 02, 2005
Sean Kelly wrote:
> Russ Lewis wrote:
> 
>>
>> I also think that it would be a good idea to handle static object composition with the same syntax as classes on the stack.  In either case, we are really declaring a class-value variable rather than a class-reference variable.
> 
> 
> Technically, it's a class reference to a stack instance as this change would not provide value semantics for classes.  The distinction is clear when considering this:
> 
> class C {}
> class D {
>     C c;
> 
>     this() {
>         c = C();
>     }
> 
>     this( int x ) {
>         c = new C();
>     }
> }
> 
> This is completely legal with the proposed semantics and would result in c referring to an invalid location if the default ctor is called. Currently, we can use placement new to fake static composition:
> 
> class E {
>     C c;
> 
>     ubyte[C.sizeof] buf;
> 
>     this() {
>         c = new (&buf[0]) C();
>     }
> }
> 
> (I'm just guessing at syntax here as I haven't actually tried this)
> 
> but this raises alignment issues and such that a language-supported method does not have.

It's a hack on top of a hack on top of a hack.  And it's all because we wanted to save typing * characters for our class variables.  (sigh)
November 02, 2005
Russ Lewis wrote:
> 
> It's a hack on top of a hack on top of a hack.  And it's all because we wanted to save typing * characters for our class variables.  (sigh)

I used to feel this way, but I'm coming around.  Adding the pointer qualifier to heap-based classes has the unfortunate consequence of requiring value semantics for their stack-based equivalent.  And while I do believe that user-defined value types can be quite useful in some circumstances, I think they also tend to be misused and are prone to creating code that is difficult to read.  So long as the language has sufficient support for higher maths and such built-in (the complex type, vector ops, etc), I don't see a pressing need for value semantics in D.

I think it's important to note that D differs fundamentally from C++ in that it does impose language-level restrictions in an attempt to reduce the amount of unreadable code and other sheer nastiness that is common in C++.  But it also provides a lot of features C++ doesn't--built into the language--to eliminate the need for such nasty code in the first place.  This definately fosters a different programming style than C++, but given the vast bulk of horrible C++ code I've encountered I think that's probably a good thing.


Sean
November 02, 2005
Sean Kelly wrote:
> Russ Lewis wrote:
> 
>> It's a hack on top of a hack on top of a hack.  And it's all because we wanted to save typing * characters for our class variables.  (sigh)
> 
> I used to feel this way, but I'm coming around.  Adding the pointer qualifier to heap-based classes has the unfortunate consequence of requiring value semantics for their stack-based equivalent.  And while I do believe that user-defined value types can be quite useful in some circumstances, I think they also tend to be misused and are prone to creating code that is difficult to read.  So long as the language has sufficient support for higher maths and such built-in (the complex type, vector ops, etc), I don't see a pressing need for value semantics in D.
> 
> I think it's important to note that D differs fundamentally from C++ in that it does impose language-level restrictions in an attempt to reduce the amount of unreadable code and other sheer nastiness that is common in C++.  But it also provides a lot of features C++ doesn't--built into the language--to eliminate the need for such nasty code in the first place.  This definately fosters a different programming style than C++, but given the vast bulk of horrible C++ code I've encountered I think that's probably a good thing.

Changing the syntax doesn't require you to change the functionality, just the syntax.  I'm actually pretty happy about the development of the language over time.  IMHO, it was a good idea to discard class-value variables at the start of development.  We all argued out whether or not they were *really* necessary.  Eventually, we came to the conclusion that they were, so they were implemented, but with restrictions.  That same process could have happened quite easliy even if we were typing * characters.

Granted, there would be a lot more flame wars about why we didn't have "basic" features.  Ick.