Jump to page: 1 2 3
Thread overview
"constantness" in D
May 26, 2005
Andrew Fedoniouk
May 26, 2005
Kris
May 26, 2005
Andrew Fedoniouk
May 28, 2005
Walter
May 28, 2005
Matthew
May 28, 2005
John Reimer
May 28, 2005
Matthew
OT -- Hiatus
May 29, 2005
John Reimer
May 30, 2005
Andrew Fedoniouk
May 26, 2005
Derek Parnell
May 26, 2005
Andrew Fedoniouk
May 26, 2005
Derek Parnell
May 26, 2005
Kris
May 26, 2005
Derek Parnell
May 26, 2005
Kris
May 30, 2005
Matthew
May 30, 2005
Andrew Fedoniouk
May 31, 2005
Brad Beveridge
Re:
May 31, 2005
Sean Kelly
May 31, 2005
Brad Beveridge
Jun 01, 2005
Matthew
Re:
Jun 01, 2005
Sean Kelly
Re:
May 26, 2005
Sam
May 26, 2005
Constness is not only about possible bugs or ROM placement of variables as
Kris rightly mentioned.
It is also about effectiveness and robustness of code and especially
libraries - components.

Example:
I have a class:

class Url
{
    char[] _domain;
    char[] _filename;
    char[] _protocol;

    static Url parse( char[] url )
   {
       char[] buffer = unescape(url); // will always dup
       _domain = buffer[a..b];
       _filename = buffer[b..c];
       _protocol = buffer[c..d];
   }
   // current implementation
   char[] domain()        { return _domain.dup; }
   char[] filename()     { return _filename.dup; }
   char[] protocol()    { return _protocol.dup; }

   // this is extremely nice to have
   char[]:const  domain()      { return _domain; }
   char[]:const  filename()     { return _filename; }
   char[]:const  protocol()     { return _protocol; }
}

As you may see without const typical and robust library
implementation  approach follows to constant "joy of GC"
as  I ***must*** do 'dup' in
char[] domain()  { return _domain.dup; }
if I want my son to reuse my code.

If you think that this example is too abstract then
take a look into std/string.d  and comments in function:

char* toStrings(char[] s)
 /+ Unfortunately, this isn't reliable....

This is a typical example when "constness" will make
D different from memory greedy C#.

IMHO: without constness char[] cannot be considered
as a solutions for strings. I am pretty sure that without constness
it is just impossible to create reliable and consistent Phobos.

To D with love,

Andrew.


May 26, 2005
I'm a strong advocate for what you describe, but it may be better to talk about this particular aspect in terms of "read only" rather than "const". The latter has a somewhat sour flavour for many, and covers such a broad gamut that its very name send shivers throughout the forum.

On the other hand, a "read only" modifer for types is just a sliver compared to C++ const ~ its worth keeping that in mind. Such a modifier would allow us to do all kinds of efficient and defensive programming, some of which you have pointed out.

- Kris


BTW; it can be awkward to get the syntax right when deal with function return values; how does one specify a read-only return?



"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:d73kfp$f72$1@digitaldaemon.com...
> Constness is not only about possible bugs or ROM placement of variables as
> Kris rightly mentioned.
> It is also about effectiveness and robustness of code and especially
> libraries - components.
>
> Example:
> I have a class:
>
> class Url
> {
>     char[] _domain;
>     char[] _filename;
>     char[] _protocol;
>
>     static Url parse( char[] url )
>    {
>        char[] buffer = unescape(url); // will always dup
>        _domain = buffer[a..b];
>        _filename = buffer[b..c];
>        _protocol = buffer[c..d];
>    }
>    // current implementation
>    char[] domain()        { return _domain.dup; }
>    char[] filename()     { return _filename.dup; }
>    char[] protocol()    { return _protocol.dup; }
>
>    // this is extremely nice to have
>    char[]:const  domain()      { return _domain; }
>    char[]:const  filename()     { return _filename; }
>    char[]:const  protocol()     { return _protocol; }
> }
>
> As you may see without const typical and robust library
> implementation  approach follows to constant "joy of GC"
> as  I ***must*** do 'dup' in
> char[] domain()  { return _domain.dup; }
> if I want my son to reuse my code.
>
> If you think that this example is too abstract then
> take a look into std/string.d  and comments in function:
>
> char* toStrings(char[] s)
>  /+ Unfortunately, this isn't reliable....
>
> This is a typical example when "constness" will make
> D different from memory greedy C#.
>
> IMHO: without constness char[] cannot be considered
> as a solutions for strings. I am pretty sure that without constness
> it is just impossible to create reliable and consistent Phobos.
>
> To D with love,
>
> Andrew.
>
>


May 26, 2005
On Wed, 25 May 2005 21:48:41 -0700, Andrew Fedoniouk wrote:

> Constness is not only about possible bugs or ROM placement of variables as
> Kris rightly mentioned.
> It is also about effectiveness and robustness of code and especially
> libraries - components.
> 
> Example:
> I have a class:
> 
> class Url
> {
>     char[] _domain;
>     char[] _filename;
>     char[] _protocol;
> 
>     static Url parse( char[] url )
>    {
>        char[] buffer = unescape(url); // will always dup
>        _domain = buffer[a..b];
>        _filename = buffer[b..c];
>        _protocol = buffer[c..d];
>    }
>    // current implementation
>    char[] domain()        { return _domain.dup; }
>    char[] filename()     { return _filename.dup; }
>    char[] protocol()    { return _protocol.dup; }
> 
>    // this is extremely nice to have
>    char[]:const  domain()      { return _domain; }
>    char[]:const  filename()     { return _filename; }
>    char[]:const  protocol()     { return _protocol; }
> }
> 
> As you may see without const typical and robust library
> implementation  approach follows to constant "joy of GC"
> as  I ***must*** do 'dup' in
> char[] domain()  { return _domain.dup; }
> if I want my son to reuse my code.

One could consider this as just a syntax or implementation issue. The addition of the ".dup" causes your object's data to be effectively const; that is 'not modifiable by the caller'.

The mechanism to make it const is to provide a copy of the data that the caller can freely mess about with if they want to. If instead, you want the mechanism to be that the compiler detects these at compile time, then we have a problem. From memory, I think the argument against that mechanism is that because there are always some way to fool the compiler (eg. in line assembler code) so if it does not report an error, the coder has a false sense of security.

The current, runtime mechanism, does not rely on a foolproof compiler, though at the cost of some performance, but it does guarantee const-ness.

I suppose one could argue for a syntax addition to more clearly state the intention of the coder. The compiler would still implement const-ness as it does now, via data copy, but the coder's desire for const would be more visible to the reader.

So maybe

   char[]:const funcA() { ... return a; }

could be identical to

   char[] funcA() { ... return a.dup; }

By the way, I notice that your class's member data is not marked private, thus anyone can modify it directly. Is that desired?

> If you think that this example is too abstract then
> take a look into std/string.d  and comments in function:
> 
> char* toStrings(char[] s)
>  /+ Unfortunately, this isn't reliable....

That isn't fair. The 'unreliable' code is commented out. You give the impression that the unreliable code is actually in the library.

> This is a typical example when "constness" will make
> D different from memory greedy C#.
> 
> IMHO: without constness char[] cannot be considered
> as a solutions for strings. I am pretty sure that without constness
> it is just impossible to create reliable and consistent Phobos.

I've described that the .dup mechanism actually does implement the concept of read-only strings, in so far as the calling functions are prevented from modifying data you don't want them to. Given that, it is therefore possible to create a reliable Phobos (with regards to strings anyhow).

-- 
Derek
Melbourne, Australia
26/05/2005 2:57:52 PM
May 26, 2005
Kris, I agree with you that "read-only" is better.
Other useful metaphor for the same entity would be also
'ownership'.  Ownership implies run-time support.
With ownership mechanism it is possible to make
constantness and "read-only-ness" across library/component
boundaries.

Ownership (or owner) could be an attribute of chunk
of memory in the heap. Only owner - object or module allocated
the chunk can modify - write to it.
Presumably ownership does not require notation change.
Just new(owner) .... and someinstance.owner attribute.

I am skiping details of implementation intentionally as
this is just a wild idea tended to start sort of brain storming on the
subject.

Any other ideas?

Andrew.





"Kris" <fu@bar.com> wrote in message news:d73m38$omb$1@digitaldaemon.com...
> I'm a strong advocate for what you describe, but it may be better to talk about this particular aspect in terms of "read only" rather than "const". The latter has a somewhat sour flavour for many, and covers such a broad gamut that its very name send shivers throughout the forum.
>
> On the other hand, a "read only" modifer for types is just a sliver
> compared
> to C++ const ~ its worth keeping that in mind. Such a modifier would allow
> us to do all kinds of efficient and defensive programming, some of which
> you
> have pointed out.
>
> - Kris
>
>
> BTW; it can be awkward to get the syntax right when deal with function return values; how does one specify a read-only return?
>
>
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:d73kfp$f72$1@digitaldaemon.com...
>> Constness is not only about possible bugs or ROM placement of variables
>> as
>> Kris rightly mentioned.
>> It is also about effectiveness and robustness of code and especially
>> libraries - components.
>>
>> Example:
>> I have a class:
>>
>> class Url
>> {
>>     char[] _domain;
>>     char[] _filename;
>>     char[] _protocol;
>>
>>     static Url parse( char[] url )
>>    {
>>        char[] buffer = unescape(url); // will always dup
>>        _domain = buffer[a..b];
>>        _filename = buffer[b..c];
>>        _protocol = buffer[c..d];
>>    }
>>    // current implementation
>>    char[] domain()        { return _domain.dup; }
>>    char[] filename()     { return _filename.dup; }
>>    char[] protocol()    { return _protocol.dup; }
>>
>>    // this is extremely nice to have
>>    char[]:const  domain()      { return _domain; }
>>    char[]:const  filename()     { return _filename; }
>>    char[]:const  protocol()     { return _protocol; }
>> }
>>
>> As you may see without const typical and robust library
>> implementation  approach follows to constant "joy of GC"
>> as  I ***must*** do 'dup' in
>> char[] domain()  { return _domain.dup; }
>> if I want my son to reuse my code.
>>
>> If you think that this example is too abstract then
>> take a look into std/string.d  and comments in function:
>>
>> char* toStrings(char[] s)
>>  /+ Unfortunately, this isn't reliable....
>>
>> This is a typical example when "constness" will make
>> D different from memory greedy C#.
>>
>> IMHO: without constness char[] cannot be considered
>> as a solutions for strings. I am pretty sure that without constness
>> it is just impossible to create reliable and consistent Phobos.
>>
>> To D with love,
>>
>> Andrew.
>>
>>
>
> 


May 26, 2005
Hi, Derek, please see below,

>> Constness is not only about possible bugs or ROM placement of variables
>> as
>> Kris rightly mentioned.
>> It is also about effectiveness and robustness of code and especially
>> libraries - components.
>>
>> Example:
>> I have a class:
>>
>> class Url
>> {
>>     char[] _domain;
>>     char[] _filename;
>>     char[] _protocol;
>>
>>     static Url parse( char[] url )
>>    {
>>        char[] buffer = unescape(url); // will always dup
>>        _domain = buffer[a..b];
>>        _filename = buffer[b..c];
>>        _protocol = buffer[c..d];
>>    }
>>    // current implementation
>>    char[] domain()        { return _domain.dup; }
>>    char[] filename()     { return _filename.dup; }
>>    char[] protocol()    { return _protocol.dup; }
>>
>>    // this is extremely nice to have
>>    char[]:const  domain()      { return _domain; }
>>    char[]:const  filename()     { return _filename; }
>>    char[]:const  protocol()     { return _protocol; }
>> }
>>
>> As you may see without const typical and robust library
>> implementation  approach follows to constant "joy of GC"
>> as  I ***must*** do 'dup' in
>> char[] domain()  { return _domain.dup; }
>> if I want my son to reuse my code.
>
> One could consider this as just a syntax or implementation issue. The addition of the ".dup" causes your object's data to be effectively const; that is 'not modifiable by the caller'.
>
> The mechanism to make it const is to provide a copy of the data that the
> caller can freely mess about with if they want to. If instead, you want
> the
> mechanism to be that the compiler detects these at compile time, then we
> have a problem. From memory, I think the argument against that mechanism
> is
> that because there are always some way to fool the compiler (eg. in line
> assembler code) so if it does not report an error, the coder has a false
> sense of security.
>
> The current, runtime mechanism, does not rely on a foolproof compiler, though at the cost of some performance, but it does guarantee const-ness.
>
> I suppose one could argue for a syntax addition to more clearly state the
> intention of the coder. The compiler would still implement const-ness as
> it
> does now, via data copy, but the coder's desire for const would be more
> visible to the reader.

Constantness is not about can I or cannot fool the compiler (I can full this
Turing machine in many ways) but rather about again efectiveness and
robustness. Yes, I can spread copy-on-write across *my*code.
But as a generic library designer I cannot force users to do this.
It is just not fair. Having my example in mind imagine how much memory
will take .dup approach for url "http://w3c.org"....
For given Url class (this is just a model - not a real one) when use cases
of modifications of its parts are rare, such memory allocation behavior
is not something I am considering as a good design.
And more - such Url is a short living class - parse-n-forget and
highly desireable to do not left traces in the sky after.

Yes, you can follow .NET way and say "memory is not a resource anymore" and allocate memory on each sneeze but I hope here is a community of realists....

Either const/read-only/ownership/whatever
either .dup with copying GC and all consequences which .NET and
Java are facing now.


>
> So maybe
>
>   char[]:const funcA() { ... return a; }
>
> could be identical to
>
>   char[] funcA() { ... return a.dup; }
>
> By the way, I notice that your class's member data is not marked private, thus anyone can modify it directly. Is that desired?

This just a mockup...

>
>> If you think that this example is too abstract then
>> take a look into std/string.d  and comments in function:
>>
>> char* toStrings(char[] s)
>>  /+ Unfortunately, this isn't reliable....
>
> That isn't fair. The 'unreliable' code is commented out. You give the impression that the unreliable code is actually in the library.

Sorry, I did not have an intention to demonstrate unreliable code. My point is inside comment itself and the solution which might be implemented (code commented out).

Consider I need to draw components of the URL  on the screen.
So on each WM_PAINT I need to allocate new strings...
Or to store them in member variables thus effectively
increase number of objects  on GC controllable perimeter.

In Java simple applet with let's say red background is
12 objects allocated on each paint. Doh! And they even asking
why it is slow.... Application is just not working 20% of time,
is it good design?

>
>> This is a typical example when "constness" will make
>> D different from memory greedy C#.
>>
>> IMHO: without constness char[] cannot be considered
>> as a solutions for strings. I am pretty sure that without constness
>> it is just impossible to create reliable and consistent Phobos.
>
> I've described that the .dup mechanism actually does implement the concept
> of read-only strings, in so far as the calling functions are prevented
> from
> modifying data you don't want them to. Given that, it is therefore
> possible
> to create a reliable Phobos (with regards to strings anyhow).

Sorry when I am speaking about reliable I am assuming that effectivness and robustness is a primordial requirements. Otherwise we will have a robust something which nobody will use.

Again, I am not agianst D, I am just trying to think of
how to make it even better.

Andrew.


May 26, 2005
On Wed, 25 May 2005 23:31:49 -0700, Andrew Fedoniouk wrote:


[snip]

> Again, I am not agianst D, I am just trying to think of
> how to make it even better.

Yeah, I know that Andrew.

So how could read-only data be implemented differently in D? Any ideas, given that a compiler can't catch all attempts to write to read-only data, and we can't really rely on the underlying hardware to help us?

-- 
Derek
Melbourne, Australia
26/05/2005 4:35:10 PM
May 26, 2005
"Derek Parnell" <derek@psych.ward> wrote
> So how could read-only data be implemented differently in D? Any ideas, given that a compiler can't catch all attempts to write to read-only data, and we can't really rely on the underlying hardware to help us?

Au Contraire, sir;

The compiler *can* catch all /accidental/ or /incidental/ attempts to write to data marked as read-only. If someone is hell-bent on circumventing that, then they can do so via assembly, or via pointer aliasing, if they really insist.

What, I believe, Andrew is getting at is where the intent of the designer is clearly stated within the (enhanced) syntax ~ the compiler supports that by flagging every instance whereby that explicit contract is implicitly broken.

One can write *cast(void *) 0 = 0; and the compiler does not stop you ~ yet the compiler goes out of its way to catch array indexing errors. Surely the same approach could be applied here; yes?




May 26, 2005
On Wed, 25 May 2005 23:56:29 -0700, Kris wrote:

> "Derek Parnell" <derek@psych.ward> wrote
>> So how could read-only data be implemented differently in D? Any ideas, given that a compiler can't catch all attempts to write to read-only data, and we can't really rely on the underlying hardware to help us?
> 
> Au Contraire, sir;
> 
> The compiler *can* catch all /accidental/ or /incidental/ attempts to write to data marked as read-only. If someone is hell-bent on circumventing that, then they can do so via assembly, or via pointer aliasing, if they really insist.

I agree that a compiler can catch 'normal' references. It was the absurd, "hell-bent" methods that I was concerned with. If we can live with that, *and* make that clear in documentation, then fine.

> What, I believe, Andrew is getting at is where the intent of the designer is clearly stated within the (enhanced) syntax ~ the compiler supports that by flagging every instance whereby that explicit contract is implicitly broken.

Yep, that's a position I can support. If a coder explicitly marks something as read-only *and* the compiler detects an infringement of that then it should report an error.

> One can write *cast(void *) 0 = 0; and the compiler does not stop you ~ yet the compiler goes out of its way to catch array indexing errors. Surely the same approach could be applied here; yes?

Seems consistent to me. But it must be made clear to coders that if the compiler does not report a read-only access error, it does not absolutely guarantee that the application is free of such problems; it just means that the compiler didn't find any.

-- 
Derek
Melbourne, Australia
26/05/2005 4:59:36 PM
May 26, 2005
"Derek Parnell" <derek@psych.ward>
> > One can write *cast(void *) 0 = 0; and the compiler does not stop you ~
yet
> > the compiler goes out of its way to catch array indexing errors. Surely
the
> > same approach could be applied here; yes?
>
> Seems consistent to me. But it must be made clear to coders that if the compiler does not report a read-only access error, it does not absolutely guarantee that the application is free of such problems; it just means
that
> the compiler didn't find any.

Aye, sir. Nor does it guarantee the algorithms are correct <g>


May 26, 2005
Come to think of it, 'const's were never always guaranteed in C++ because one could do a 'const_cast<typename>(variable)' to remove the const-ness.

So

I guess....

Nothing is ever 'const' in this world.....
Everything changes........
'const' isn't what it used to be, or ever was????

Sam-
sam987883@yahoo.com
« First   ‹ Prev
1 2 3