www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Pure, Nothrow in Generic Programming

reply dsimcha <dsimcha yahoo.com> writes:
One issue that should ideally be resolved before D2 is finalized that I meant
to bring up here a long time ago is how to handle pure and nothrow in generic
functions.  For example:

T max(T)(T lhs, T rhs) {
    return (lhs > rhs) ? lhs : rhs;
}

Obviously, if T is an int, max can be pure nothrow.  However, if T is some
user defined type, then who knows?  I've run into a few cases where I'm
writing a pure function that needs to call something simple like
std.algorithm.max() on an int or a float and invariably I end up just
rewriting a max function for my specific type and marking it as pure nothrow.
 This is obviously a suboptimial solution.

Since the source needs to be available anyhow for templates to be usable, my
proposal would be for pure/nothrow functions to be able to call templated
functions that are not marked as pure/nothrow as long as they would compile if
marked pure/nothrow.  Also, I think that we need to establish a strong
convention, for objects, that opCmp, opEquals and a few other "standard"
functions should always be const pure nothrow, and that it is acceptable for
any library code (mixins, etc.) to assume this.
Nov 22 2009
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Sun, 22 Nov 2009 20:34:21 +0100, dsimcha <dsimcha yahoo.com> wrote:

 One issue that should ideally be resolved before D2 is finalized that I  
 meant
 to bring up here a long time ago is how to handle pure and nothrow in  
 generic
 functions.  For example:

 T max(T)(T lhs, T rhs) {
     return (lhs > rhs) ? lhs : rhs;
 }

 Obviously, if T is an int, max can be pure nothrow.  However, if T is  
 some
 user defined type, then who knows?  I've run into a few cases where I'm
 writing a pure function that needs to call something simple like
 std.algorithm.max() on an int or a float and invariably I end up just
 rewriting a max function for my specific type and marking it as pure  
 nothrow.
  This is obviously a suboptimial solution.

 Since the source needs to be available anyhow for templates to be  
 usable, my
 proposal would be for pure/nothrow functions to be able to call templated
 functions that are not marked as pure/nothrow as long as they would  
 compile if
 marked pure/nothrow.  Also, I think that we need to establish a strong
 convention, for objects, that opCmp, opEquals and a few other "standard"
 functions should always be const pure nothrow, and that it is acceptable  
 for
 any library code (mixins, etc.) to assume this.

Votes++; -- Simen
Nov 25 2009
prev sibling parent reply Don <nospam nospam.com> writes:
dsimcha wrote:
 One issue that should ideally be resolved before D2 is finalized that I meant
 to bring up here a long time ago is how to handle pure and nothrow in generic
 functions.  For example:
 
 T max(T)(T lhs, T rhs) {
     return (lhs > rhs) ? lhs : rhs;
 }
 
 Obviously, if T is an int, max can be pure nothrow.  However, if T is some
 user defined type, then who knows?  I've run into a few cases where I'm
 writing a pure function that needs to call something simple like
 std.algorithm.max() on an int or a float and invariably I end up just
 rewriting a max function for my specific type and marking it as pure nothrow.
  This is obviously a suboptimial solution.
 
 Since the source needs to be available anyhow for templates to be usable, my
 proposal would be for pure/nothrow functions to be able to call templated
 functions that are not marked as pure/nothrow as long as they would compile if
 marked pure/nothrow. 

That sounds reasonable to me. Already in many cases, the function body must be analysed in order to determine the return type, so it must also be analysed to determine its pure/nothrow-ness. Implementation might be tricky, though. Also, I think that we need to establish a strong
 convention, for objects, that opCmp, opEquals and a few other "standard"
 functions should always be const pure nothrow, and that it is acceptable for
 any library code (mixins, etc.) to assume this.

And what about safe ? BTW, it worries me a little that safe, pure, and ability to be used in CTFE are concepts which have about 90% overlap. Yet none is a subset of another.
Nov 25 2009
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Don (nospam nospam.com)'s article
 dsimcha wrote:
 One issue that should ideally be resolved before D2 is finalized that I meant
 to bring up here a long time ago is how to handle pure and nothrow in generic
 functions.  For example:

 T max(T)(T lhs, T rhs) {
     return (lhs > rhs) ? lhs : rhs;
 }

 Obviously, if T is an int, max can be pure nothrow.  However, if T is some
 user defined type, then who knows?  I've run into a few cases where I'm
 writing a pure function that needs to call something simple like
 std.algorithm.max() on an int or a float and invariably I end up just
 rewriting a max function for my specific type and marking it as pure nothrow.
  This is obviously a suboptimial solution.

 Since the source needs to be available anyhow for templates to be usable, my
 proposal would be for pure/nothrow functions to be able to call templated
 functions that are not marked as pure/nothrow as long as they would compile if
 marked pure/nothrow.

must be analysed in order to determine the return type, so it must also be analysed to determine its pure/nothrow-ness. Implementation might be tricky, though. Also, I think that we need to establish a strong
 convention, for objects, that opCmp, opEquals and a few other "standard"
 functions should always be const pure nothrow, and that it is acceptable for
 any library code (mixins, etc.) to assume this.


I would say that safe doesn't make much sense. What if you're implementing your comparison function using memcmp() or something else that involves a bunch of pointers? If you pass memcmp() invalid parameters, it can segfault, and would therefore have to be marked as unsafe, meaning that safe functions couldn't call it.
Nov 25 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 I would say that  safe doesn't make much sense.  What if you're implementing
your
 comparison function using memcmp() or something else that involves a bunch of
 pointers?  If you pass memcmp() invalid parameters, it can segfault, and would
 therefore have to be marked as unsafe, meaning that safe functions couldn't
call it.

A safe function is only safe if the parameters passed to it are valid. memcmp() cannot be safe as it does pointer arithmetic.
Nov 27 2009
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 I would say that  safe doesn't make much sense.  What if you're implementing
your
 comparison function using memcmp() or something else that involves a bunch of
 pointers?  If you pass memcmp() invalid parameters, it can segfault, and would
 therefore have to be marked as unsafe, meaning that safe functions couldn't


 A safe function is only safe if the parameters passed to it are valid.
 memcmp() cannot be safe as it does pointer arithmetic.

I think you misunderstood the argument. memcmp() could be trusted if functions only need to be safe when passed valid parameters, though I don't necessarily agree that this makes sense. I was thinking memcmp() shouldn't even be marked trusted because it's so easy to invoke undefined behavior by passing incorrect parameters. This would mean that, if opCmp() uses it, opCmp() couldn't be marked as safe.
Nov 27 2009
next sibling parent reply Don <nospam nospam.com> writes:
dsimcha wrote:
 == Quote from Walter Bright (newshound1 digitalmars.com)'s article
 dsimcha wrote:
 I would say that  safe doesn't make much sense.  What if you're implementing
your
 comparison function using memcmp() or something else that involves a bunch of
 pointers?  If you pass memcmp() invalid parameters, it can segfault, and would
 therefore have to be marked as unsafe, meaning that safe functions couldn't


 A safe function is only safe if the parameters passed to it are valid.
 memcmp() cannot be safe as it does pointer arithmetic.

I think you misunderstood the argument. memcmp() could be trusted if functions only need to be safe when passed valid parameters, though I don't necessarily agree that this makes sense. I was thinking memcmp() shouldn't even be marked trusted because it's so easy to invoke undefined behavior by passing incorrect parameters. This would mean that, if opCmp() uses it, opCmp() couldn't be marked as safe.

It seems to me that one of the most important features of SafeD is that whenever a safe function invokes a function, it does so only with valid parameters. The problem with memcmp() is that the required relationship between the parameters is complicated, and can't be determined statically by the compiler. The fact that internally it does pointer arithmetic is a symptom of this problem: it might be accessing memory which is not implied by the parameters. So memcmp() cannot be trusted. Likewise, if it contains asm, it might be accessing non-parameter memory. OTOH, this contains pointer arithmetic but is perfectly fine: bool ptrcmp(char *x, char *y) { char *z = x+100; return y < z; }
Nov 27 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 It seems to me that one of the most important features of SafeD is that 
 whenever a  safe function invokes a function, it does so only with valid 
 parameters. The problem with memcmp() is that the required relationship 
 between the parameters is complicated, and can't be determined 
 statically by the compiler.
 The fact that internally it does pointer arithmetic is a symptom of this 
 problem: it might be accessing memory which is not implied by the 
 parameters. So memcmp() cannot be  trusted.

Exactly. You said it better than me!
Nov 27 2009
prev sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted if
functions
 only need to be safe when passed valid parameters, though I don't necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even be marked
  trusted because it's so easy to invoke undefined behavior by passing incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp() couldn't be
marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.
Nov 27 2009
next sibling parent BCS <none anon.com> writes:
Hello Walter,

 there's no
 way that an  safe function can guarantee it sends memcmp() arguments
 that will work safely with memcmp().

I think that's backwards. There's no way memcmp can be sure it's arguments are safe just because it's being called from a safe function. OTOH, if a trusted function can do the needed checks, then so can a safe function. The problem is that there is is no way for DMD to check that it has; thus the trusted wrapper.
Nov 27 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted if 
 functions
 only need to be safe when passed valid parameters, though I don't 
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even 
 be marked
  trusted because it's so easy to invoke undefined behavior by passing 
 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp() 
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei
Nov 27 2009
next sibling parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted 
 if functions
 only need to be safe when passed valid parameters, though I don't 
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even 
 be marked
  trusted because it's so easy to invoke undefined behavior by passing 
 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp() 
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei

Although Walter had previously talked about making safe a little stronger than just memory safety -- with the goal of eliminating undefined behaviour. So (b) would be a problem. After all, you could you use the same argument to say that array bounds checking isn't required for reads, only for writes.
Nov 27 2009
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Don (nospam nospam.com)'s article
 Andrei Alexandrescu wrote:
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted
 if functions
 only need to be safe when passed valid parameters, though I don't
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even
 be marked
  trusted because it's so easy to invoke undefined behavior by passing
 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp()
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei

stronger than just memory safety -- with the goal of eliminating undefined behaviour. So (b) would be a problem. After all, you could you use the same argument to say that array bounds checking isn't required for reads, only for writes.

Quick question about the eliminating undefined behavior thing: Isn't overflowing a signed int undefined behavior? If so, how would we eliminate undefined behavior without very expensive runtime checks?
Nov 27 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
 Isn't overflowing a signed int undefined behavior?

Yes, it can be.
If so, how would we eliminate undefined behavior without very expensive runtime
checks?<

I have explained LLVM devs how to speed-up some of those runtime checks. Do you exactly know how much expensive they are, in synthetic benchmarks or real programs? (I have done few tests in dotnet C#, that has a switch to activate those runtime tests, results are not conclusive). Do you prefer a less buggy program or a fast&buggy program? There are ways to infer and remove at compile time part of those tests (or sometimes pull them out of loops). Bye, bearophile
Nov 27 2009
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Denis Koroskin:

 I don't think integer overflow could be considered an undefined behavior.  
 It's pretty much expected that uint.max + 1 == 0.

Computers are (mostly) deterministic, so in a certain sense everything they do can be expected :-) But sometimes the programmer "forgets" or doesn't take into account that a number can be int.max, so the overflow can be unexpected for him/her. The same can be said for array bounds, the expected that a write past the array end will give troubles, but having bound tests is often useful anyway, because it helps catch programming errors, etc. Bye, bearophile
Nov 27 2009
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Denis Koroskin (2korden gmail.com)'s article
 On Sat, 28 Nov 2009 00:20:47 +0300, dsimcha <dsimcha yahoo.com> wrote:
 == Quote from Don (nospam nospam.com)'s article
 Andrei Alexandrescu wrote:
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted
 if functions
 only need to be safe when passed valid parameters, though I don't
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even
 be marked
  trusted because it's so easy to invoke undefined behavior by



 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp()
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's


 way that an  safe function can guarantee it sends memcmp() arguments
 that will work safely with memcmp().

 Whoever calls memcmp() can be marked  trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result

 c) incorrect addresses outside the application, segfault

 None of the above is unsafe. So memcmp is safe. (In contrast, memcpy

 not). Color me surprised but convinced.


 Andrei

stronger than just memory safety -- with the goal of eliminating undefined behaviour. So (b) would be a problem. After all, you could you use the same argument to say that array bounds checking isn't required for reads, only for writes.

Quick question about the eliminating undefined behavior thing: Isn't overflowing a signed int undefined behavior? If so, how would we eliminate undefined behavior without very expensive runtime checks?

It's pretty much expected that uint.max + 1 == 0.

What about int.max + 1? I specifically mentioned **signed** integers because, IIRC overflowing these is undefined in C, but overflowing unsigned is defined.
Nov 27 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 What about int.max + 1?  I specifically mentioned **signed** integers because,
 IIRC overflowing these is undefined in C, but overflowing unsigned is defined.

It's undefined behavior in C because C supports ones-complement arithmetic. D does not - twos-complement only.
Nov 27 2009
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
dsimcha wrote:
 Quick question about the eliminating undefined behavior thing:  Isn't
overflowing
 a signed int undefined behavior?

No. On every 2's complement machine I've ever heard of, the behavior is defined and the same.
Nov 27 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Don wrote:
 Andrei Alexandrescu wrote:
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted 
 if functions
 only need to be safe when passed valid parameters, though I don't 
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even 
 be marked
  trusted because it's so easy to invoke undefined behavior by 
 passing incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp() 
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei

Although Walter had previously talked about making safe a little stronger than just memory safety -- with the goal of eliminating undefined behaviour. So (b) would be a problem.

I think it would be implementation-defined behavior - in case (b) memcmp would return an implementation-defined value but still defined.
 After all, you could you 
 use the same argument to say that array bounds checking isn't required 
 for reads, only for writes.

Well less so. Reading an array element off-bounds that's of an elaborate type with indirections will lead to UB. Andrei
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 b) incorrect addresses within the application, erroneous result returned


I think it would be implementation-defined behavior - in case (b) memcmp would return an implementation-defined value but still defined.

How could it?
Nov 27 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 Andrei Alexandrescu wrote:
 b) incorrect addresses within the application, erroneous result 
 returned


I think it would be implementation-defined behavior - in case (b) memcmp would return an implementation-defined value but still defined.

How could it?

The value itself does not matter. The point is the behavior is not undefined. Undefined behavior = anything within the realm of physical possibility could happen. Implementation-defined behavior = the behavior depends on the implementation. In the memcmp case, the behavior is always defined to return an int or to never return (segfault). The value of the int for incorrect inputs is implementation dependent because it depends on the way data of various objects is laid out in memory. The fact that the definition is complex does not render it undefined. Let's not confuse undefined with implementation-defined. I am firmly convinced that memcmp never falls in the undefined behavior realm. The behavior is always defined. Andrei
Nov 27 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 Let's not confuse undefined with implementation-defined. I am firmly 
 convinced that memcmp never falls in the undefined behavior realm. The 
 behavior is always defined.

Makes sense. But I'd still want to make it not safe, by using a more expansive definition of safe to include some implementation defined behaviors.
Nov 27 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 Andrei Alexandrescu wrote:
 Let's not confuse undefined with implementation-defined. I am firmly 
 convinced that memcmp never falls in the undefined behavior realm. The 
 behavior is always defined.

Makes sense. But I'd still want to make it not safe, by using a more expansive definition of safe to include some implementation defined behaviors.

It's funny how we are trading places. Til now I was the stickler for safety. I agree with the noble spirit, but not with the lack of precision. To me the main attraction of safe is that it has a very clear definition. For example, that allows me to sleep at night in spite of ~=. You want to define safe more loosely and more judgement-call-ish depending on how you feel about various particular cases. I don't like that. First, it means that now safety becomes a subjective matter. People on the newsgroup can now argue forever about how various idioms should or shouldn't be safe. Bartosz is getting the debating equivalent of a Gatling gun because now he can credibly argue that ~= could be considered not safe. Finally, if you're in a bad mood because your shoes are too tight one day, something will not be safe that should be. All that I don't like at all. It's not science, not engineering, and not even design. It's just doing things by ear. We've spent literally the past few years trying to eliminate such things from D, so we shouldn't counter that with a completely subjective call. Andrei
Nov 27 2009
parent torhu <no spam.invalid> writes:
I have a feeling that the safeD thing is a bit premature.  I'm only 
posting this because then I can link to this post next summer, when it's 
becoming clear that I was right.  Because I'm such a nice guy I won't 
even save this link.  :P

Noone's ever tried this feature in real code that people actually get 
paid for writing, have they?  And no, Phobos doesn't count until it's 
gotten more use of the kind that where you have a boss that decied if 
you get money or not.

By 'get paid for writing' I mean exactly what any sane person with 
industry experince would mean.
Nov 27 2009
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Denis Koroskin wrote:
 On Fri, 27 Nov 2009 23:51:44 +0300, Andrei Alexandrescu 
 <SeeWebsiteForEmail erdani.org> wrote:
 
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted 
 if functions
 only need to be safe when passed valid parameters, though I don't 
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even 
 be marked
  trusted because it's so easy to invoke undefined behavior by 
 passing incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp() 
 couldn't be marked
 as  safe.

because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei

Points 2 and 3 introduce undefined behavior, which is not allowed in SafeD :p

s/undefined/implementation-defined/ Andrei
Nov 27 2009
parent reply Rainer Deyke <rainerd eldwood.com> writes:
Andrei Alexandrescu wrote:
 Denis Koroskin wrote:
 Points 2 and 3 introduce undefined behavior, which is not allowed in
 SafeD :p

s/undefined/implementation-defined/

Behavior is only implementation-defined if the implementation actually defines it. When targeting a specific implementation of a language, there is no difference between implementation-defined behavior and just plain defined behavior. I think the term you are looking for is "non-deterministic", which describes an operation which is defined to have one of several possible effects, but which of these effects actually takes place is not defined. Incidentally, it is sometimes possible to send output to a physical device by merely reading from a memory-mapped I/O address. Therefore the set of possible results of memcmp includes sending garbage output to a physical device. -- Rainer Deyke - rainerd eldwood.com
Nov 27 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Rainer Deyke wrote:
 Andrei Alexandrescu wrote:
 Denis Koroskin wrote:
 Points 2 and 3 introduce undefined behavior, which is not allowed in
 SafeD :p


Behavior is only implementation-defined if the implementation actually defines it. When targeting a specific implementation of a language, there is no difference between implementation-defined behavior and just plain defined behavior. I think the term you are looking for is "non-deterministic", which describes an operation which is defined to have one of several possible effects, but which of these effects actually takes place is not defined. Incidentally, it is sometimes possible to send output to a physical device by merely reading from a memory-mapped I/O address. Therefore the set of possible results of memcmp includes sending garbage output to a physical device.

I only know of writing to cause actual device writing, so I'd be interested in a link that shows otherwise. Anyhow, this is a pretty good argument; reading some memory-mapped cache could cause other pages to be written etc. Andrei
Nov 30 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Fri, 27 Nov 2009 23:51:44 +0300, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted if  
 functions
 only need to be safe when passed valid parameters, though I don't  
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even  
 be marked
  trusted because it's so easy to invoke undefined behavior by passing  
 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp()  
 couldn't be marked
 as  safe.

because trusted functions can be called by safe ones, but there's no way that an safe function can guarantee it sends memcmp() arguments that will work safely with memcmp(). Whoever calls memcmp() can be marked trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result returned c) incorrect addresses outside the application, segfault None of the above is unsafe. So memcmp is safe. (In contrast, memcpy is not). Color me surprised but convinced. Andrei

Points 2 and 3 introduce undefined behavior, which is not allowed in SafeD :p
Nov 27 2009
prev sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sat, 28 Nov 2009 00:20:47 +0300, dsimcha <dsimcha yahoo.com> wrote:

 == Quote from Don (nospam nospam.com)'s article
 Andrei Alexandrescu wrote:
 Walter Bright wrote:
 dsimcha wrote:
 I think you misunderstood the argument.  memcmp() could be  trusted
 if functions
 only need to be safe when passed valid parameters, though I don't
 necessarily
 agree that this makes sense.  I was thinking memcmp() shouldn't even
 be marked
  trusted because it's so easy to invoke undefined behavior by  



 incorrect
 parameters.  This would mean that, if opCmp() uses it, opCmp()
 couldn't be marked
 as  safe.

memcmp() could be marked trusted, but it should not be. This is because trusted functions can be called by safe ones, but there's


 way that an  safe function can guarantee it sends memcmp() arguments
 that will work safely with memcmp().

 Whoever calls memcmp() can be marked  trusted.

Hm, if we think of it, memcmp can be safe no problem. This is beacuse it oly reads stuff. There are three possible outcomes: a) valid addresses, all's fine b) incorrect addresses within the application, erroneous result

 c) incorrect addresses outside the application, segfault

 None of the above is unsafe. So memcmp is safe. (In contrast, memcpy  

 not). Color me surprised but convinced.


 Andrei

stronger than just memory safety -- with the goal of eliminating undefined behaviour. So (b) would be a problem. After all, you could you use the same argument to say that array bounds checking isn't required for reads, only for writes.

Quick question about the eliminating undefined behavior thing: Isn't overflowing a signed int undefined behavior? If so, how would we eliminate undefined behavior without very expensive runtime checks?

I don't think integer overflow could be considered an undefined behavior. It's pretty much expected that uint.max + 1 == 0.
Nov 27 2009