September 14, 2009
Brad Roberts wrote:
> Walter Bright wrote:
>> strlen() is safe, while strcpy() and printf() are not.
> 
> You sure?  Does running beyond the bounds of the array if there's no null
> termination count as safe some how? :)

Yes. Memory safety is defined as being free of memory corruption errors. Simply reading memory out of bounds does not corrupt memory.

Note that it is ok for a memory safe program to generate a seg fault.

printf() is not memory safe because of the %n format.
September 15, 2009
Don wrote:
> Rainer Deyke wrote:
>> Don't forget that "uses floating point" is a transitive property.  Any pure function that calls a pure-but-unmemoisable function is itself pure-but-unmemoisable.
> 
> This is incorrect.

Then I must have misunderstood your proposal.  Either you did a poor job of explaining it, or I did a poor job of trying to understand it, or it's not as simple as you make it out to be.

Since I'm not really interested in discussing the details of floating point rounding modes and memoisation, I'll just leave it at that.

>> Is there any real need to treat floating point state differently from other global state in regard to "pure"?
> 
> Yes. Because it's all-pervasive.

It only affects floating point operations.  Other pieces of global state (e.g. the global locale) affect other operations.  Once you make a special case for floating point mode, it's easy to argue that the special case should be extended to other pieces of global data.  A general solution generally beats special cases.

Or maybe I'm completely overthinking this.

> Unless you treat it specially, you
> cannot use floating point in any pure function. That creates a
> restriction which is so severe that 'pure' becomes useless. Something
> like the following template function could not be pure:
> 
> T add(T a, T b) { return a + b; }

In the presence of structs and class executing arbitrary code in opPlus, you can't make this pure anyway.  Unless you force opPlus itself to be pure, which is almost certainly too restrictive for the current definition of pure.


-- 
Rainer Deyke - rainerd@eldwood.com
September 15, 2009
Rainer Deyke wrote:
> Don wrote:
>> Rainer Deyke wrote:
>>> Don't forget that "uses floating point" is a transitive property.  Any
>>> pure function that calls a pure-but-unmemoisable function is itself
>>> pure-but-unmemoisable.
>> This is incorrect.
> 
> Then I must have misunderstood your proposal.  Either you did a poor job
> of explaining it, or I did a poor job of trying to understand it, or
> it's not as simple as you make it out to be.

> Since I'm not really interested in discussing the details of floating
> point rounding modes and memoisation, I'll just leave it at that.

The description I just gave of it was
The thing you missed is that the non-memoisable pure functions can only read the global state.

> 
>>> Is there any real need to treat floating point state differently from
>>> other global state in regard to "pure"?
>> Yes. Because it's all-pervasive.
> 
> It only affects floating point operations.  Other pieces of global state
> (e.g. the global locale) affect other operations. 

But you ALWAYS have a choice about that. You can rewrite functions which are independent of locale, or you can pass the locale as a parameter. With floating point, you don't have that option.

BTW, global locales suck, big time. The idea that you can specify the formatting in the form of a locale is clearly the creation of someone who had never worked in an international environment. (And any locale which includes 'currency' is clearly the creation of an idiot).

 Once you make a
> special case for floating point mode, it's easy to argue that the
> special case should be extended to other pieces of global data.

No, because this is a hardware special case. All the other cases can be dealt with in software.

> Or maybe I'm completely overthinking this.
> 
>> Unless you treat it specially, you
>> cannot use floating point in any pure function. That creates a
>> restriction which is so severe that 'pure' becomes useless. Something
>> like the following template function could not be pure:
>>
>> T add(T a, T b) { return a + b; }
> 
> In the presence of structs and class executing arbitrary code in opPlus,
> you can't make this pure anyway.  Unless you force opPlus itself to be
> pure, which is almost certainly too restrictive for the current
> definition of pure.

You're right. Bad example. But seriously, people give sqrt(x) as the classic example of a pure function.
September 15, 2009
Walter Bright wrote:
> Brad Roberts wrote:
>> Walter Bright wrote:
>>> strlen() is safe, while strcpy() and printf() are not.
>>
>> You sure?  Does running beyond the bounds of the array if there's no null
>> termination count as safe some how? :)
> 
> Yes. Memory safety is defined as being free of memory corruption errors. Simply reading memory out of bounds does not corrupt memory.

It does result in undefined behaviour, though. I don't see much difference. (Corrupting memory is a problem only because you read it again afterwards...)

> Note that it is ok for a memory safe program to generate a seg fault.

It'd be OK if it was guaranteed to generate a seg fault. But I don't think that's true here.

> 
> printf() is not memory safe because of the %n format.
September 15, 2009
Don wrote:
> The thing you missed is that the non-memoisable pure functions can only read the global state.

No, I saw that.  But if a (pure) function calls another (pure) function
that depends on global state, then the first (pure) function also
depends on global state.

int global_state;

pure int f() {
  return global_state;
}

pure int g() {
  return f();
}

int h() {
  global_state = 5;
  return g();
}

> But you ALWAYS have a choice about that. You can rewrite functions which are independent of locale, or you can pass the locale as a parameter. With floating point, you don't have that option.

True.  Unless you add functions/operators that use a fixed rounding mode to the language.

> BTW, global locales suck, big time. The idea that you can specify the formatting in the form of a locale is clearly the creation of someone who had never worked in an international environment. (And any locale which includes 'currency' is clearly the creation of an idiot).

No argument there.


-- 
Rainer Deyke - rainerd@eldwood.com
September 16, 2009
Rainer Deyke wrote:
> Don wrote:
>> The thing you missed is that the non-memoisable pure functions can only
>> read the global state.
> 
> No, I saw that.  But if a (pure) function calls another (pure) function
> that depends on global state, then the first (pure) function also
> depends on global state.
> 
> int global_state;
> 
> pure int f() {
>   return global_state;
> }
> 
> pure int g() {
>   return f();
> }
> 
> int h() {
>   global_state = 5;
>   return g();
> }

Ah. The important thing that makes this work is that the global FP state has a clearly defined default. (round-to-nearest, full precision, no floating point exceptions enabled). Part of the implicit contract of calling a 'memoisable pure' function is that the global FP state is in the default state.
No pure function can change the state. So once you're in a memoisable pure function, you can safely call any non-memoisable pure function, in the knowledge that the default mode is in effect.

> 
>> But you ALWAYS have a choice about that. You can rewrite functions which
>> are independent of locale, or you can pass the locale as a parameter.
>> With floating point, you don't have that option.
> 
> True.  Unless you add functions/operators that use a fixed rounding mode
> to the language.

Yes, there's a few impractical ways it could be made to work (passing the rounding mode as an explicit parameter to every function is another option).

Actually there's a related issue which I haven't mentioned: the floating point exception sticky flags are effectively a global variable, written to by every floating point operation which you perform. It can be covered in the same way: there's no guarantee that the flags will be correct in the presence of memoisation, so you need to be able to indicate to the compiler or runtime that the flags returned from this function call are important to you.
September 16, 2009
Don wrote:
> Ah. The important thing that makes this work is that the global FP state has a clearly defined default. (round-to-nearest, full precision, no floating point exceptions enabled). Part of the implicit contract of calling a 'memoisable pure' function is that the global FP state is in the default state.

Then I'm not sure it makes to treat "memoisable" as a property of a (pure) function.  It seems more like a property of the context from which the function is called.  *All* pure function are memoisable if you always call them with the floating point rounding mode set to the default.  Conversely, all pure functions can be called with an arbitrary rounding mode if you treat them an unmemoisable.

Some function - those that don't perform any floating point calculation, directly or indirectly - are independent from floating point state, and could even memoised even when called with an arbitrary floating point state.  But there is no good way to automatically detect these functions.


-- 
Rainer Deyke - rainerd@eldwood.com
September 17, 2009
Rainer Deyke wrote:
> Don wrote:
>> Ah. The important thing that makes this work is that the global FP state
>> has a clearly defined default. (round-to-nearest, full precision, no
>> floating point exceptions enabled). Part of the implicit contract of
>> calling a 'memoisable pure' function is that the global FP state is in
>> the default state.
> 
> Then I'm not sure it makes to treat "memoisable" as a property of a
> (pure) function.  It seems more like a property of the context from
> which the function is called.  *All* pure function are memoisable if you
> always call them with the floating point rounding mode set to the
> default.  Conversely, all pure functions can be called with an arbitrary
> rounding mode if you treat them an unmemoisable.

That is correct.

> Some function - those that don't perform any floating point calculation,
> directly or indirectly - are independent from floating point state, and
> could even memoised even when called with an arbitrary floating point
> state.  But there is no good way to automatically detect these functions.

It sounds as though you never saw my proposal. My proposal was that, by analogy to module(system), specific modules should be marked, for example:
module (advancedfloatingpoint, system) std.math;
or:
module (nondefaultfloat, system) std.math;

All pure functions are memoisable except for pure advancedfloatingpoint functions when called from a function (pure or not) which is also in an advancedfloatingpoint module.

This is a very tiny hole in the 'purity' rules, and is a tiny addition to the language, but it's enough to cover  the practical uses of floating-point rounding and exception flags.
1 2 3 4
Next ›   Last »