July 18, 2006
Bruno Medeiros wrote:
>> Can you suggest another solution other than avoiding const-checking entirely? By the way, a dedicated string class is actually an implementation of runtime const checking.
>>> but, it's certainly not a pretty solution... and there's a related question - how can tolower know whether to .dup or not.. there are certainly cases where it isn't necessary.
>> This is just another issue that static checking can't solve but runtime checking can (providing we have a modification of the libraries to support a CoW and a in-place version).
> 
> I'm not following you. That code example shows how a static const checking should work, so what is the problem with that?
> And in:
>   char[] name_m = tolower(name);
>   // Can we modify name_m? Better dup it, just to make sure
> You ask if we can modify name_m, the answer is yes if the return type of tolower is non-const, no if it const, so what's the issue here?

You seem to have ignored my more recent example. The problem is that static checking *forces* the return value to be const, which in turn forces you to dup it. You don't always need to do that:

>> char[] tolower(const char[] input) /* the input must be const, because we agree with CoW, so we won't change it */
>> {
>>   // do some stuff
>>   if ( a write is necessary )
>>   { /* copy it into another variable, since we can't change input it's const)*/
>>   }
>>   return something; /* This something could possibly be input, so it also needs to be declared const. So we go back and make the return value of the function also a const. */
>> }
>>
>> // Now, since the return value is const, we *must* dup it.
>>
July 20, 2006
Reiner Pope wrote:
> Bruno Medeiros wrote:
>>> Can you suggest another solution other than avoiding const-checking entirely? By the way, a dedicated string class is actually an implementation of runtime const checking.
>>>> but, it's certainly not a pretty solution... and there's a related question - how can tolower know whether to .dup or not.. there are certainly cases where it isn't necessary.
>>> This is just another issue that static checking can't solve but runtime checking can (providing we have a modification of the libraries to support a CoW and a in-place version).
>>
>> I'm not following you. That code example shows how a static const checking should work, so what is the problem with that?
>> And in:
>>   char[] name_m = tolower(name);
>>   // Can we modify name_m? Better dup it, just to make sure
>> You ask if we can modify name_m, the answer is yes if the return type of tolower is non-const, no if it const, so what's the issue here?
> 
> You seem to have ignored my more recent example. The problem is that static checking *forces* the return value to be const, which in turn forces you to dup it. You don't always need to do that:
> 
>  >> char[] tolower(const char[] input) /* the input must be const, because we agree with CoW, so we won't change it */
>  >> {
>  >>   // do some stuff
>  >>   if ( a write is necessary )
>  >>   { /* copy it into another variable, since we can't change input it's const)*/
>  >>   }
>  >>   return something; /* This something could possibly be input, so it also needs to be declared const. So we go back and make the return value of the function also a const. */
>  >> }
>  >>
>  >> // Now, since the return value is const, we *must* dup it.
>  >>

Are you saying that in that function, what is returned sometimes needs do be const(readonly) and sometimes not? And because of that the function needs to return const everytime?
But then why not have the function return non-const and do the duping when necessary?

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 20, 2006
Bruno Medeiros wrote:
> Reiner Pope wrote:
>> Bruno Medeiros wrote:
>>>> Can you suggest another solution other than avoiding const-checking entirely? By the way, a dedicated string class is actually an implementation of runtime const checking.
>>>>> but, it's certainly not a pretty solution... and there's a related question - how can tolower know whether to .dup or not.. there are certainly cases where it isn't necessary.
>>>> This is just another issue that static checking can't solve but runtime checking can (providing we have a modification of the libraries to support a CoW and a in-place version).
>>>
>>> I'm not following you. That code example shows how a static const checking should work, so what is the problem with that?
>>> And in:
>>>   char[] name_m = tolower(name);
>>>   // Can we modify name_m? Better dup it, just to make sure
>>> You ask if we can modify name_m, the answer is yes if the return type of tolower is non-const, no if it const, so what's the issue here?
>>
>> You seem to have ignored my more recent example. The problem is that static checking *forces* the return value to be const, which in turn forces you to dup it. You don't always need to do that:
>>
>>  >> char[] tolower(const char[] input) /* the input must be const, because we agree with CoW, so we won't change it */
>>  >> {
>>  >>   // do some stuff
>>  >>   if ( a write is necessary )
>>  >>   { /* copy it into another variable, since we can't change input it's const)*/
>>  >>   }
>>  >>   return something; /* This something could possibly be input, so it also needs to be declared const. So we go back and make the return value of the function also a const. */
>>  >> }
>>  >>
>>  >> // Now, since the return value is const, we *must* dup it.
>>  >>
> 
> Are you saying that in that function, what is returned sometimes needs do be const(readonly) and sometimes not? 

Yes.

And because of that the
> function needs to return const everytime?
> But then why not have the function return non-const and do the duping when necessary?

Doesn't help.

Either, the function has to dup every time (even if the input was a const, and it's passing it on unmodified) -- so that a user of the function can write without copying first

OR the user of the function has to dup every time (even if it was already duped)

In both cases, you have an unnecessary dup.


July 21, 2006
Don Clugston wrote:
> Bruno Medeiros wrote:
>> Reiner Pope wrote:
>>> Bruno Medeiros wrote:
>>>>> Can you suggest another solution other than avoiding const-checking entirely? By the way, a dedicated string class is actually an implementation of runtime const checking.
>>>>>> but, it's certainly not a pretty solution... and there's a related question - how can tolower know whether to .dup or not.. there are certainly cases where it isn't necessary.
>>>>> This is just another issue that static checking can't solve but runtime checking can (providing we have a modification of the libraries to support a CoW and a in-place version).
>>>>
>>>> I'm not following you. That code example shows how a static const checking should work, so what is the problem with that?
>>>> And in:
>>>>   char[] name_m = tolower(name);
>>>>   // Can we modify name_m? Better dup it, just to make sure
>>>> You ask if we can modify name_m, the answer is yes if the return type of tolower is non-const, no if it const, so what's the issue here?
>>>
>>> You seem to have ignored my more recent example. The problem is that static checking *forces* the return value to be const, which in turn forces you to dup it. You don't always need to do that:
>>>
>>>  >> char[] tolower(const char[] input) /* the input must be const, because we agree with CoW, so we won't change it */
>>>  >> {
>>>  >>   // do some stuff
>>>  >>   if ( a write is necessary )
>>>  >>   { /* copy it into another variable, since we can't change input it's const)*/
>>>  >>   }
>>>  >>   return something; /* This something could possibly be input, so it also needs to be declared const. So we go back and make the return value of the function also a const. */
>>>  >> }
>>>  >>
>>>  >> // Now, since the return value is const, we *must* dup it.
>>>  >>
>>
>> Are you saying that in that function, what is returned sometimes needs do be const(readonly) and sometimes not? 
> 
> Yes.
> 
> And because of that the
>> function needs to return const everytime?
>> But then why not have the function return non-const and do the duping when necessary?
> 
> Doesn't help.
> 
> Either, the function has to dup every time (even if the input was a const, and it's passing it on unmodified) -- so that a user of the function can write without copying first
> 
> OR the user of the function has to dup every time (even if it was already duped)
> 
> In both cases, you have an unnecessary dup.
> 
> 

Ok, I'm not following you guys. Can you explain from scratch what it is you were trying to achieve (the purpose of the function?), which when done with static const checking causes unnecessary dups?


-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 21, 2006
> Ok, I'm not following you guys. Can you explain from scratch what it is you were trying to achieve (the purpose of the function?), which when done with static const checking causes unnecessary dups?

It's really simple. Say you have a function that sometimes modifies its data and sometimes doesn't. The non-const version is simple, as it's allowed in-place modification:

byte[] filter(byte[] data)
{
    if (...)
        data[0] = 10;
    return data;
}

Now, whenever you have const data, you can only use it by duping:

const byte[] data = foo();
byte[] filtered = filter(data.dup);

That's bad, because you always have to .dup the data, even if filter() does nothing with it. So, you also write a const version:

const byte[] filter(const byte[] data)
{
    if (...) {
        byte[] result = data.dup;
        result[0] = 10;
        return result;
    }
    return data;
}

That's much better, because a copy is only made when needed. However, there's still a problem - the return type must be const, because you need to be able to return the original (const) parameter. Therefore, the information about whether a copy is made is lost.

With a single function that's not even a problem, but say your filtering is configurable and you call 20 filters. If you use the const versions, 20 copies will be made, even though only one is necessary. If you use the non-const versions, you're forced to dup before the first filter,
even when not necessary at all.

A similar problem occurs in this case:

const char[] handleDesc()
{
    if (_handle) {
        return format("Handle #%d", _handle.id());
    } else {
        return "No handle";
    }
}

Because you sometimes return a literal, you must declare the result const, even though you'll return a fresh writable char[] most of the time, which may or may not be significant. Alternatively, you can .dup the literal before returning it, but it will usually be a wasted .dup..

In both cases, the problem is the same - there is no way for the function to return information about whether a copy was made along with the data itself. It can't even neatly be solved by wrapping the thing in a struct or checking equality of references, because the type in either case is static and one way or another, you'll have to work around that (by casting or whatever)


xs0
July 27, 2006
xs0 wrote:
> 
>> Ok, I'm not following you guys. Can you explain from scratch what it is you were trying to achieve (the purpose of the function?), which when done with static const checking causes unnecessary dups?
> 
> It's really simple. Say you have a function that sometimes modifies its data and sometimes doesn't. The non-const version is simple, as it's allowed in-place modification:
> 
> byte[] filter(byte[] data)
> {
>     if (...)
>         data[0] = 10;
>     return data;
> }
> 
> Now, whenever you have const data, you can only use it by duping:
> 
> const byte[] data = foo();
> byte[] filtered = filter(data.dup);
> 
> That's bad, because you always have to .dup the data, even if filter() does nothing with it. So, you also write a const version:
> 
> const byte[] filter(const byte[] data)
> {
>     if (...) {
>         byte[] result = data.dup;
>         result[0] = 10;
>         return result;
>     }
>     return data;
> }
> 
> That's much better, because a copy is only made when needed. However, there's still a problem - the return type must be const, because you need to be able to return the original (const) parameter. Therefore, the information about whether a copy is made is lost.
> 
> With a single function that's not even a problem, but say your filtering is configurable and you call 20 filters. If you use the const versions, 20 copies will be made, even though only one is necessary. If you use the non-const versions, you're forced to dup before the first filter,
> even when not necessary at all.
> 
> A similar problem occurs in this case:
> 
> const char[] handleDesc()
> {
>     if (_handle) {
>         return format("Handle #%d", _handle.id());
>     } else {
>         return "No handle";
>     }
> }
> 
> Because you sometimes return a literal, you must declare the result const, even though you'll return a fresh writable char[] most of the time, which may or may not be significant. Alternatively, you can .dup the literal before returning it, but it will usually be a wasted .dup..
> 
> In both cases, the problem is the same - there is no way for the function to return information about whether a copy was made along with the data itself. It can't even neatly be solved by wrapping the thing in a struct or checking equality of references, because the type in either case is static and one way or another, you'll have to work around that (by casting or whatever)
> 
> 
> xs0

Ah, I understand the objective now.

But then, this problem you are trying to solve here is one of performance only, related to ownership management, but not necessarily the same. In particular:

* Whatever mechanism is made to deal with that problem, cannot be disabled in release builds: it is not a contract, unlike const/ownership checking which is a contract, and being so can be checked at compile time, or at runtime in debug releases only.

* For that same reasons, such mechanism should not be a substitute for const/ownership checking, since this latter one can be processed at compile time, which is naturally more efficient, and the former one can't.

* Such mechanism is likely impractical or too hard to implement in the general sense (that is, for any data type). So perhaps the mechanism should be implement not by the language/compiler, but by the coder with existing language constructs (mixins, etc.)?

-- 
Bruno Medeiros - CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
July 27, 2006
> Ah, I understand the objective now.
> 
> But then, this problem you are trying to solve here is one of performance only, related to ownership management, but not necessarily the same. In particular:

> * Whatever mechanism is made to deal with that problem, cannot be disabled in release builds: it is not a contract, unlike const/ownership checking which is a contract, and being so can be checked at compile time, or at runtime in debug releases only.

Well, it is a contract (though shall not modify a readonly array), just not verifiable at compile-time. Similar to in{} and out{} blocks, I guess.. It has other (potentially significant) benefits, though..

> * For that same reasons, such mechanism should not be a substitute for const/ownership checking, since this latter one can be processed at compile time, which is naturally more efficient, and the former one can't.

I disagree about efficiency - it turns out there is negligible speed impact even if .readonly is not used at all, while it can be used for significant speed improvements with simpler code (in particular, writing a fast and safe COW function is easier). I posted test results and code in digitalmars.D, if you're interested (I think :)

> * Such mechanism is likely impractical or too hard to implement in the general sense (that is, for any data type). So perhaps the mechanism should be implement not by the language/compiler, but by the coder with existing language constructs (mixins, etc.)?

Well, you could code your own array references (like I did for my test), but they lose on ease of use and are less flexible in general (because you can't code an inheritance tree which would mimic the built-in arrays'). On the other hand, if it was language-supported, nothing would be lost, and something would be gained..


xs0
1 2
Next ›   Last »