www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - const / readonly - a little honesty, please

reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
Just wanted to give a counter to Walter's recent const propaganda.

const in C++ is an incredibly useful tool, and can be used - both in its 
intended/designed way, and in unforeseen ways - as a very powerful 
compile-time design enforcement mechanism. For anyone willing to brave 
all 628 pages, I discuss many of these in Imperfect C++.

Sure, it has its flaws. No-one pretends that that's not so. Indeed, my 
latest "Flexible C++" instalment, called "Beware Logical Constness" 
(http://www.cuj.com/documents/cujexp0502wilson/), discusses how logical 
constness + multithreading is a dangerous combination.

What Walter seems never to acknowledge with C++, or, at best, to couch 
in terms of irrelevance, is that const is (or at least has become) 
primarily important for communicating design constraints.

Almost without exception, I couldn't give a flying fig whether the 
compiler puts my const variables in ROM, nor whether the compiler is 
prevented from making certain optimisations for fear of my constness 
being logical and not physical. I value const as a design enforcement 
mechanism. And, for that purpose, I have a hard time not considering 
anyone who stipulates it to be valueless as either dishonest or 
ignorant, because it is so manifestly demonstrable to be extremely 
useful.

Let me lay out what I think is the crucial difference between mine and 
Walter's positions, and why you should all be wary of believing either 
of us to be 100% correct on this subject. Walter is first and foremost a 
compiler writer, and as such he sees const as a flawed idea because of 
(i) the fact that it is useless for optimisation, and (ii) it adds a lot 
of complexity. He (apparently) couldn't care less about its usefulness 
in helping the compiler to enforce the programmer's design.

I am first and foremost a library writer, and as such see const to be a 
*hugely* successful idea because (i) it allows me to express highly 
important semantics to the users of my code, and (ii) it allows me to 
protect my code against misuse. I (admittedly) couldn't give a stuff 
about its ROMifications, and am largely unconcerned by the ability to 
subvert physical constness for logical constness (though I remain 
mindful of the dangers therein when I need to; hence the recent 
"Flexible C++" instalment mentioned above.)

Now, what I've recently asked for is a small, specific subset of C++'s 
const, namely in the enforcement of explicit instantiation of members. 
This has got NOTHING to do with truely const things that can go in ROM. 
It has got NOTHING to do with any type of physical / logical const 
subversion. And, unless I'm a complete moron, it will add VERY LITTLE 
complexity into the compiler.

But what it _will_ do is prevent errors of omission in the 
initialisation of the members of types in non-trivial constructors, and 
thereby make D a better language than it currently is for producing 
robust code. (That'd be a good thing, no?).

And do you know how I know this to be true, rather than just conjecture 
and pro-const propaganda? Because I made precisely that error of 
omission in the writing of Database.this() in std.openrj!!

If it helps people keep away from all the irrelevant arguments I've 
covered above, let's call it the 'explicit' keyword. It would be used as 
in the following example:

class X
{
public
    this(int i)
    {
        y = i;
        z = 1;
    } // y == i, z == 1

    this(long i)
    {
        z = 1;
    } // y == 0, z == 1

    this(short s)
    {
        y = s;
    } // COMPILE ERROR: explicit member 'z' not explicitly initialised

private:
    int                y;
    explicit int    z;
}


Now, please please please can we have on-point opinions on this 
particular facet of C++'s multifaceted const facility? I challenge 
anyone to demonstrate how having this facility will not be a manifest 
improvement in code correctness.


(Note: adding the 'explicit' keyword will not be a waste at all. I have 
several other plans for it, the seeds of which may be found dotted 
throughout Imperfect C++ <g> ...)



-- 
Matthew Wilson

Author: "Imperfect C++", Addison-Wesley, 2004
    (http://www.imperfectcplusplus.com)
Contributing editor, C/C++ Users Journal
    (http://www.synesis.com.au/articles.html#columns)
Director, Synesis Software
    (www.synesis.com.au)
STLSoft moderator
    (http://www.stlsoft.org)

Synesis Software Pty Ltd
P.O.Box 125
Waverley
New South Wales, 2024
Australia

-----------------------------------------------------
Mar 09 2005
next sibling parent reply Kris <Kris_member pathlink.com> writes:
Does the compiler also complain if you assign an explicit more than once? If so,
then this could be considered similar to 'final' variables in other languages.
I've often found a need for the latter in D (particularly with singletons), and
had to fudge it through various means. 

If this is not the same thing, then I'd like to ask for a 'final' ... in
/addition/ to what you're describing. They are related, and they do catch
implementation errors at compile-time.

- Kris


In article <d0nua5$di5$1 digitaldaemon.com>, Matthew says...
Just wanted to give a counter to Walter's recent const propaganda.

const in C++ is an incredibly useful tool, and can be used - both in its 
intended/designed way, and in unforeseen ways - as a very powerful 
compile-time design enforcement mechanism. For anyone willing to brave 
all 628 pages, I discuss many of these in Imperfect C++.

Sure, it has its flaws. No-one pretends that that's not so. Indeed, my 
latest "Flexible C++" instalment, called "Beware Logical Constness" 
(http://www.cuj.com/documents/cujexp0502wilson/), discusses how logical 
constness + multithreading is a dangerous combination.

What Walter seems never to acknowledge with C++, or, at best, to couch 
in terms of irrelevance, is that const is (or at least has become) 
primarily important for communicating design constraints.

Almost without exception, I couldn't give a flying fig whether the 
compiler puts my const variables in ROM, nor whether the compiler is 
prevented from making certain optimisations for fear of my constness 
being logical and not physical. I value const as a design enforcement 
mechanism. And, for that purpose, I have a hard time not considering 
anyone who stipulates it to be valueless as either dishonest or 
ignorant, because it is so manifestly demonstrable to be extremely 
useful.

Let me lay out what I think is the crucial difference between mine and 
Walter's positions, and why you should all be wary of believing either 
of us to be 100% correct on this subject. Walter is first and foremost a 
compiler writer, and as such he sees const as a flawed idea because of 
(i) the fact that it is useless for optimisation, and (ii) it adds a lot 
of complexity. He (apparently) couldn't care less about its usefulness 
in helping the compiler to enforce the programmer's design.

I am first and foremost a library writer, and as such see const to be a 
*hugely* successful idea because (i) it allows me to express highly 
important semantics to the users of my code, and (ii) it allows me to 
protect my code against misuse. I (admittedly) couldn't give a stuff 
about its ROMifications, and am largely unconcerned by the ability to 
subvert physical constness for logical constness (though I remain 
mindful of the dangers therein when I need to; hence the recent 
"Flexible C++" instalment mentioned above.)

Now, what I've recently asked for is a small, specific subset of C++'s 
const, namely in the enforcement of explicit instantiation of members. 
This has got NOTHING to do with truely const things that can go in ROM. 
It has got NOTHING to do with any type of physical / logical const 
subversion. And, unless I'm a complete moron, it will add VERY LITTLE 
complexity into the compiler.

But what it _will_ do is prevent errors of omission in the 
initialisation of the members of types in non-trivial constructors, and 
thereby make D a better language than it currently is for producing 
robust code. (That'd be a good thing, no?).

And do you know how I know this to be true, rather than just conjecture 
and pro-const propaganda? Because I made precisely that error of 
omission in the writing of Database.this() in std.openrj!!

If it helps people keep away from all the irrelevant arguments I've 
covered above, let's call it the 'explicit' keyword. It would be used as 
in the following example:

class X
{
public
    this(int i)
    {
        y = i;
        z = 1;
    } // y == i, z == 1

    this(long i)
    {
        z = 1;
    } // y == 0, z == 1

    this(short s)
    {
        y = s;
    } // COMPILE ERROR: explicit member 'z' not explicitly initialised

private:
    int                y;
    explicit int    z;
}


Now, please please please can we have on-point opinions on this 
particular facet of C++'s multifaceted const facility? I challenge 
anyone to demonstrate how having this facility will not be a manifest 
improvement in code correctness.


(Note: adding the 'explicit' keyword will not be a waste at all. I have 
several other plans for it, the seeds of which may be found dotted 
throughout Imperfect C++ <g> ...)



-- 
Matthew Wilson

Author: "Imperfect C++", Addison-Wesley, 2004
    (http://www.imperfectcplusplus.com)
Contributing editor, C/C++ Users Journal
    (http://www.synesis.com.au/articles.html#columns)
Director, Synesis Software
    (www.synesis.com.au)
STLSoft moderator
    (http://www.stlsoft.org)

Synesis Software Pty Ltd
P.O.Box 125
Waverley
New South Wales, 2024
Australia

-----------------------------------------------------

Mar 09 2005
next sibling parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Kris" <Kris_member pathlink.com> wrote in message 
news:d0nvsl$fn7$1 digitaldaemon.com...
 Does the compiler also complain if you assign an explicit more than 
 once? If so,
 then this could be considered similar to 'final' variables in other 
 languages.
 I've often found a need for the latter in D (particularly with 
 singletons), and
 had to fudge it through various means.

 If this is not the same thing, then I'd like to ask for a 'final' ... 
 in
 /addition/ to what you're describing. They are related, and they do 
 catch
 implementation errors at compile-time.

 - Kris

Very good point. Being as how I prefer to make the decisions when it comes to writing my code, I'd maybe suggest that we can have permutations of int x; explict int x; final int x; explicit final int x; But that may be deemed overly complex.
Mar 09 2005
parent xs0 <xs0 xs0.com> writes:
Well, as far as Java goes, if you declare something as final, you need 
to set it in all constructors (if it's not already set within the 
declaration). If a constructor calls another constructor that 
initializes it, it's also fine.. If there is no constructor, it's an 
invalid class, if a constructor doesn't initialize it, it's an invalid 
constructor.

So this is not exactly what you'd like (because it includes the var 
being a constant), but I guess there are few cases where you'd both like 
to definitely initialize something and to also have it changeable 
(because if it's not final, you can simply uninitialize it later, so you 
again have no guarantee), so perhaps a solution is to simply adopt those 
final semantics (it would also make Java people switching to D happier :).


xs0


Matthew wrote:
 "Kris" <Kris_member pathlink.com> wrote in message 
 news:d0nvsl$fn7$1 digitaldaemon.com...
 
Does the compiler also complain if you assign an explicit more than 
once? If so,
then this could be considered similar to 'final' variables in other 
languages.
I've often found a need for the latter in D (particularly with 
singletons), and
had to fudge it through various means.

If this is not the same thing, then I'd like to ask for a 'final' ... 
in
/addition/ to what you're describing. They are related, and they do 
catch
implementation errors at compile-time.

- Kris

Very good point. Being as how I prefer to make the decisions when it comes to writing my code, I'd maybe suggest that we can have permutations of int x; explict int x; final int x; explicit final int x; But that may be deemed overly complex.

Mar 09 2005
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 9 Mar 2005 23:12:22 +0000 (UTC), Kris <Kris_member pathlink.com>  
wrote:
 Does the compiler also complain if you assign an explicit more than  
 once? If so,
 then this could be considered similar to 'final' variables in other  
 languages.
 I've often found a need for the latter in D (particularly with  
 singletons), and
 had to fudge it through various means.

 If this is not the same thing, then I'd like to ask for a 'final' ... in
 /addition/ to what you're describing. They are related, and they do catch
 implementation errors at compile-time.

Doesn't 'final' (in those languages) require that the variable be given a value where it's declared i.e. class A { final int a = 5; } of course we could diverge from this and allow class A { final int a; this() { a = 5; //omit this and get an error. } } which is what Matthew is after. Regan
 - Kris


 In article <d0nua5$di5$1 digitaldaemon.com>, Matthew says...
 Just wanted to give a counter to Walter's recent const propaganda.

 const in C++ is an incredibly useful tool, and can be used - both in its
 intended/designed way, and in unforeseen ways - as a very powerful
 compile-time design enforcement mechanism. For anyone willing to brave
 all 628 pages, I discuss many of these in Imperfect C++.

 Sure, it has its flaws. No-one pretends that that's not so. Indeed, my
 latest "Flexible C++" instalment, called "Beware Logical Constness"
 (http://www.cuj.com/documents/cujexp0502wilson/), discusses how logical
 constness + multithreading is a dangerous combination.

 What Walter seems never to acknowledge with C++, or, at best, to couch
 in terms of irrelevance, is that const is (or at least has become)
 primarily important for communicating design constraints.

 Almost without exception, I couldn't give a flying fig whether the
 compiler puts my const variables in ROM, nor whether the compiler is
 prevented from making certain optimisations for fear of my constness
 being logical and not physical. I value const as a design enforcement
 mechanism. And, for that purpose, I have a hard time not considering
 anyone who stipulates it to be valueless as either dishonest or
 ignorant, because it is so manifestly demonstrable to be extremely
 useful.

 Let me lay out what I think is the crucial difference between mine and
 Walter's positions, and why you should all be wary of believing either
 of us to be 100% correct on this subject. Walter is first and foremost a
 compiler writer, and as such he sees const as a flawed idea because of
 (i) the fact that it is useless for optimisation, and (ii) it adds a lot
 of complexity. He (apparently) couldn't care less about its usefulness
 in helping the compiler to enforce the programmer's design.

 I am first and foremost a library writer, and as such see const to be a
 *hugely* successful idea because (i) it allows me to express highly
 important semantics to the users of my code, and (ii) it allows me to
 protect my code against misuse. I (admittedly) couldn't give a stuff
 about its ROMifications, and am largely unconcerned by the ability to
 subvert physical constness for logical constness (though I remain
 mindful of the dangers therein when I need to; hence the recent
 "Flexible C++" instalment mentioned above.)

 Now, what I've recently asked for is a small, specific subset of C++'s
 const, namely in the enforcement of explicit instantiation of members.
 This has got NOTHING to do with truely const things that can go in ROM.
 It has got NOTHING to do with any type of physical / logical const
 subversion. And, unless I'm a complete moron, it will add VERY LITTLE
 complexity into the compiler.

 But what it _will_ do is prevent errors of omission in the
 initialisation of the members of types in non-trivial constructors, and
 thereby make D a better language than it currently is for producing
 robust code. (That'd be a good thing, no?).

 And do you know how I know this to be true, rather than just conjecture
 and pro-const propaganda? Because I made precisely that error of
 omission in the writing of Database.this() in std.openrj!!

 If it helps people keep away from all the irrelevant arguments I've
 covered above, let's call it the 'explicit' keyword. It would be used as
 in the following example:

 class X
 {
 public
    this(int i)
    {
        y = i;
        z = 1;
    } // y == i, z == 1

    this(long i)
    {
        z = 1;
    } // y == 0, z == 1

    this(short s)
    {
        y = s;
    } // COMPILE ERROR: explicit member 'z' not explicitly initialised

 private:
    int                y;
    explicit int    z;
 }


 Now, please please please can we have on-point opinions on this
 particular facet of C++'s multifaceted const facility? I challenge
 anyone to demonstrate how having this facility will not be a manifest
 improvement in code correctness.


 (Note: adding the 'explicit' keyword will not be a waste at all. I have
 several other plans for it, the seeds of which may be found dotted
 throughout Imperfect C++ <g> ...)



 --
 Matthew Wilson

 Author: "Imperfect C++", Addison-Wesley, 2004
    (http://www.imperfectcplusplus.com)
 Contributing editor, C/C++ Users Journal
    (http://www.synesis.com.au/articles.html#columns)
 Director, Synesis Software
    (www.synesis.com.au)
 STLSoft moderator
    (http://www.stlsoft.org)

 Synesis Software Pty Ltd
 P.O.Box 125
 Waverley
 New South Wales, 2024
 Australia

 -----------------------------------------------------


Mar 09 2005
parent "Carlos Santander B." <csantander619 gmail.com> writes:
Regan Heath wrote:
 
 Doesn't 'final' (in those languages) require that the variable be given 
 a  value where it's declared i.e.
 
 class A {
   final int a = 5;
 }
 

I also always thought that "final" in Java was a replacement for "const" (besides meaning not virtual).
 of course we could diverge from this and allow
 
 class A {
   final int a;
   this() {
     a = 5; //omit this and get an error.
   }
 }
 
 which is what Matthew is after.
 

Right now, "final" isn't documented (AFAIK), so I think that's a reasonable idea (I mean, it's not like it's set in stone what it does).
 Regan
 

_______________________ Carlos Santander Bernal
Mar 09 2005
prev sibling next sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Matthew wrote:

 If it helps people keep away from all the irrelevant arguments I've 
 covered above, let's call it the 'explicit' keyword. It would be used as 
 in the following example:
 
 class X
 {
 public
     this(int i)
     {
         y = i;
         z = 1;
     } // y == i, z == 1
 
     this(long i)
     {
         z = 1;
     } // y == 0, z == 1
 
     this(short s)
     {
         y = s;
     } // COMPILE ERROR: explicit member 'z' not explicitly initialised
 
 private:
     int                y;
     explicit int    z;
 }

This sounds a lot like how "final" works in Java:
 class X
 {
     public X (int i)
     {
         y = i;
         z = 1;
     } // y == i, z == 1
 
     public X (long i)
     {
         z = 1;
     } // y == 0, z == 1
 
     public X (char s)
     {
         y = s;
     } // COMPILE ERROR: explicit member 'z' not explicitly initialised
 
     private int          y;
     private final int    z;
 }

And it actually does give an error similar to what you describe:
 *** Semantic Error: The blank final field "z" must be initialized in
 this and every constructor which does not call a form of this(); or
 else once in an instance initializer block or instance field initializer.

BTW; I normally use Jikes for compiling my Java (doesn't everyone ?) Javac says a more boring: "variable z might not have been initialized" --anders
Mar 09 2005
prev sibling next sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Matthew wrote:

 Almost without exception, I couldn't give a flying fig whether the 
 compiler puts my const variables in ROM, nor whether the compiler is 
 prevented from making certain optimisations for fear of my constness 
 being logical and not physical. I value const as a design enforcement 
 mechanism. And, for that purpose, I have a hard time not considering 
 anyone who stipulates it to be valueless as either dishonest or 
 ignorant, because it is so manifestly demonstrable to be extremely 
 useful.

I think "const" in the meaning of "readonly" could help with the string literals blowing up in your face when you assign to them ? (not happening on Windows, unless the compiler uses string pooling) Like this change in a certain C++ compiler: http://msdn.microsoft.com/library/en-us/vclang/html/ vclrfstringliteralshavepropertypeofconstchar%5B%5D.asp
 String literals now have the type const char [] and are now placed in a
 read-only section of memory. Changing that memory will now cause an
 access violation. Code compiled in previous versions using /GF will also
 cause the access violation.

It could also help with "remembering" to use Copy-on-Write ? Like in C++ terms:
 #define READONLY const
 
 char *upperstr(READONLY char *str)
 {
   // Copy-on-Write
   char *copy = strdup(str);
   assert(copy != NULL);
   return upperstr(copy);
 }
 
 char *upperstr(char *str)
 {
   int i, len;
 
   len = strlen(str);
   for (i = 0; i < len; i++)
   {
     char c = str[i];
     str[i] = toupper(c);
   }
 
   return str;
 }

So that it would use the correct version, with string literals ? With D, there's no difference between the two routines - except that the bottom one forgets to .dup, and thus can't handle ""... It might even help people to stay off the toString() value ? Little things like that. Name it "readonly" if const is bad... Some suggested using "in" vs. "out" here, but that would apply to the value of str - right? (as in the pointer, not the chars) --anders
Mar 09 2005
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
Most certainly this issue needs to be resolved. I have no clear idea 
how, and suspect that it needs the wisdom and insight of big-W to come 
up with the solution.

One thing I do know: all operating systems should have identical 
behaviour in this regard.



"Anders F Björklund" <afb algonet.se> wrote in message 
news:d0o1p4$hf5$1 digitaldaemon.com...
 Matthew wrote:

 Almost without exception, I couldn't give a flying fig whether the 
 compiler puts my const variables in ROM, nor whether the compiler is 
 prevented from making certain optimisations for fear of my constness 
 being logical and not physical. I value const as a design enforcement 
 mechanism. And, for that purpose, I have a hard time not considering 
 anyone who stipulates it to be valueless as either dishonest or 
 ignorant, because it is so manifestly demonstrable to be extremely 
 useful.

I think "const" in the meaning of "readonly" could help with the string literals blowing up in your face when you assign to them ? (not happening on Windows, unless the compiler uses string pooling) Like this change in a certain C++ compiler: http://msdn.microsoft.com/library/en-us/vclang/html/ vclrfstringliteralshavepropertypeofconstchar%5B%5D.asp
 String literals now have the type const char [] and are now placed in 
 a
 read-only section of memory. Changing that memory will now cause an
 access violation. Code compiled in previous versions using /GF will 
 also
 cause the access violation.

It could also help with "remembering" to use Copy-on-Write ? Like in C++ terms:
 #define READONLY const

 char *upperstr(READONLY char *str)
 {
   // Copy-on-Write
   char *copy = strdup(str);
   assert(copy != NULL);
   return upperstr(copy);
 }

 char *upperstr(char *str)
 {
   int i, len;

   len = strlen(str);
   for (i = 0; i < len; i++)
   {
     char c = str[i];
     str[i] = toupper(c);
   }

   return str;
 }

So that it would use the correct version, with string literals ? With D, there's no difference between the two routines - except that the bottom one forgets to .dup, and thus can't handle ""... It might even help people to stay off the toString() value ? Little things like that. Name it "readonly" if const is bad... Some suggested using "in" vs. "out" here, but that would apply to the value of str - right? (as in the pointer, not the chars) --anders

Mar 09 2005
parent xs0 <xs0 xs0.com> writes:
How about

func(int[in] arr); // I won't touch the contents

func(int[inout] arr); // I may, same as the default

func(int[out] arr); // I won't read them, but will write

The last one is different from "out int[]" because it still gets the 
length and allocated memory, and is useful for declaring that the 
contents of the array don't influence the result.

Then there's the fun with

func(out int[in] arr); // illegal, can't have read-only to null :)
func(out int[inout] arr); // illegal, can't read from null
func(out int[out] arr); // the [out] has no effect, so prolly illegal
                         // too


func(inout int[in] arr); // I won't touch the original array,
                          // but may return a different one (cool
                          // when the original is sliced somewhere
                          // else) (CoW, basically)

func(inout int[inout] arr); // I may do anything

func(inout int[out] arr); // I may reuse the array or not (perhaps
                           // to avoid reallocation), but I don't
                           // care about its contents


Thoughts?


xs0


Matthew wrote:
 Most certainly this issue needs to be resolved. I have no clear idea 
 how, and suspect that it needs the wisdom and insight of big-W to come 
 up with the solution.
 
 One thing I do know: all operating systems should have identical 
 behaviour in this regard.
 
 
 
 "Anders F Björklund" <afb algonet.se> wrote in message 
 news:d0o1p4$hf5$1 digitaldaemon.com...
 
Matthew wrote:


Almost without exception, I couldn't give a flying fig whether the 
compiler puts my const variables in ROM, nor whether the compiler is 
prevented from making certain optimisations for fear of my constness 
being logical and not physical. I value const as a design enforcement 
mechanism. And, for that purpose, I have a hard time not considering 
anyone who stipulates it to be valueless as either dishonest or 
ignorant, because it is so manifestly demonstrable to be extremely 
useful.

I think "const" in the meaning of "readonly" could help with the string literals blowing up in your face when you assign to them ? (not happening on Windows, unless the compiler uses string pooling) Like this change in a certain C++ compiler: http://msdn.microsoft.com/library/en-us/vclang/html/ vclrfstringliteralshavepropertypeofconstchar%5B%5D.asp
String literals now have the type const char [] and are now placed in 
a
read-only section of memory. Changing that memory will now cause an
access violation. Code compiled in previous versions using /GF will 
also
cause the access violation.

It could also help with "remembering" to use Copy-on-Write ? Like in C++ terms:
#define READONLY const

char *upperstr(READONLY char *str)
{
  // Copy-on-Write
  char *copy = strdup(str);
  assert(copy != NULL);
  return upperstr(copy);
}

char *upperstr(char *str)
{
  int i, len;

  len = strlen(str);
  for (i = 0; i < len; i++)
  {
    char c = str[i];
    str[i] = toupper(c);
  }

  return str;
}

So that it would use the correct version, with string literals ? With D, there's no difference between the two routines - except that the bottom one forgets to .dup, and thus can't handle ""... It might even help people to stay off the toString() value ? Little things like that. Name it "readonly" if const is bad... Some suggested using "in" vs. "out" here, but that would apply to the value of str - right? (as in the pointer, not the chars) --anders


Mar 10 2005
prev sibling next sibling parent "Charlie Patterson" <charliep1 excite.com> writes:
"Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message 
news:d0nua5$di5$1 digitaldaemon.com...

 class X
 {
 public
    this(short s)
    {
        y = s;
    } // COMPILE ERROR: explicit member 'z' not explicitly initialised

 private:
    int                y;
    explicit int    z;
 }

I personally like const, even when flawed. However your example sounds trivial. As a library writer you want to make sure that any variable you have gone out of your way to mark 'explicit' then cries foul in your *own* constructors if not set. Sure it might save a bug or two, but it's not much. Libraries get vetted quickly enough. The app writer using your libraries doesn't get squat for all this. Or as you point out, there is no semantics passed up. While I'm not used to in, out, inout, and I don't like looking at them, they seem to cover your point about semantics.
Mar 10 2005
prev sibling parent reply "Lynn Allan" <l_d_allan adelphia.net> writes:
 I am first and foremost a library writer, and as such see const to

 *hugely* successful idea because (i) it allows me to express highly
 important semantics to the users of my code

<alert comment="newbie who may not understand the issues"> Seems like your advocated usage of "const" for library routines can be more or less accomplished with "in" parameters? The "consumer" of your library wouldn't/shouldn't care about other variables that are presumably hidden/private. </alert>
Mar 10 2005
next sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Lynn Allan" <l_d_allan adelphia.net> wrote in message 
news:d0rd7c$128k$1 digitaldaemon.com...
 I am first and foremost a library writer, and as such see const to

 *hugely* successful idea because (i) it allows me to express highly
 important semantics to the users of my code

<alert comment="newbie who may not understand the issues"> Seems like your advocated usage of "const" for library routines can be more or less accomplished with "in" parameters? The "consumer" of your library wouldn't/shouldn't care about other variables that are presumably hidden/private. </alert>

Hmmm. I could give several answers, but since I've been somewhat snappish/boorish lately, I'll conjure a nice one <g>: "I am flattered that you obviously assume that library writers are infallible, but unfortunately they're not. Therefore, they are (almost) as much in need of assistance from compilers as 'normal' programmers." That ok? :-)
Mar 10 2005
prev sibling parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Lynn Allan wrote:

 Seems like your advocated usage of "const" for library routines can be
 more or less accomplished with "in" parameters?

Note: All parameters are "in", unless declared as "out" or "inout"... The only way that this could apply to, say char[] parameters, if if they were "extended" to something like "char[out]" or so ? Currently "in" only applies to the array (or pointer) itself, and *not* to the actual characters that it is referencing. The D language at the moment treats all parameters as readonly, and suggests using the Copy-on-Write 'idiom'. But does not enforce it. It's a little like with the implicit cast of "bar[]" into "bar*", it can be convenient and less typing, and it can also hide bugs ? --anders
Mar 11 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Fri, 11 Mar 2005 09:22:55 +0100, Anders F Björklund wrote:

 Lynn Allan wrote:
 
 Seems like your advocated usage of "const" for library routines can be
 more or less accomplished with "in" parameters?

Note: All parameters are "in", unless declared as "out" or "inout"... The only way that this could apply to, say char[] parameters, if if they were "extended" to something like "char[out]" or so ? Currently "in" only applies to the array (or pointer) itself, and *not* to the actual characters that it is referencing. The D language at the moment treats all parameters as readonly, and suggests using the Copy-on-Write 'idiom'. But does not enforce it. It's a little like with the implicit cast of "bar[]" into "bar*", it can be convenient and less typing, and it can also hide bugs ? --anders

Agreed. The Copy-on-Write idiom being suggested by Walter, places the responsibility of preserving the referred-to data on the writer of the routine being called. In other words, if one is writing a routine, and that routine can receive reference parameters that are 'in' types, eg. char[], or Class instances, etc...), the one is expected to take a copy of the referred-to data *if* one is going to modify it (for any reason). Except if the *purpose* of the routine is to modify the referred-to data /in place/. For example, a ToUpperCase() routine might have been designed to change the string in situ. Or it might have been designed to return an modified string but leave the original intact. However, because one can never be certain that the routine writer has used this idiom, it is 'safer' to pass a reference to a copy of the data instead of a reference to the original data. It would be nice if we could get the compiler to help us error prone coders. If would just tell the compiler that my intention is to *not* change some referred-to data, then the compiler could alert me to code that actually is known to change the data. This alone would be a great advance in being able to express the coder's intentions and thus reduce mistakes in source code. I do understand that there are some cases in which the compiler cannot detect that some referred-to data will actually be changed, but I'm happy to live with that because that is exactly what we have now. However, there are times when the compiler *can* detect unintentional attempts to alter 'preserved' data. Please notice that I have not used the keyword 'const' in the above discussion. That terminology is obvious overloaded, and I hoped instead to just talk in plain simple English. -- Derek Parnell Melbourne, Australia 11/03/2005 11:12:39 PM
Mar 11 2005
parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
[snip]
 However, because one can never be certain that the routine writer has used
 this idiom, it is 'safer' to pass a reference to a copy of the data 
 instead
 of a reference to the original data.

 It would be nice if we could get the compiler to help us error prone
 coders. If would just tell the compiler that my intention is to *not*
 change some referred-to data, then the compiler could alert me to code 
 that
 actually is known to change the data. This alone would be a great advance
 in being able to express the coder's intentions and thus reduce mistakes 
 in
 source code.

The compiler/lint can give a warning when a char[], wchar[] or dchar[] "in" parameter is modified in place. The warning would say "modifying string input parameter - possible violation of copy-on-write". They would then search around for copy-on-write in the doc and learn about the "right" way. [snip] -Ben
Mar 11 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Fri, 11 Mar 2005 07:48:55 -0500, Ben Hinkle wrote:

 [snip]
 However, because one can never be certain that the routine writer has used
 this idiom, it is 'safer' to pass a reference to a copy of the data 
 instead
 of a reference to the original data.

 It would be nice if we could get the compiler to help us error prone
 coders. If would just tell the compiler that my intention is to *not*
 change some referred-to data, then the compiler could alert me to code 
 that
 actually is known to change the data. This alone would be a great advance
 in being able to express the coder's intentions and thus reduce mistakes 
 in
 source code.

The compiler/lint can give a warning when a char[], wchar[] or dchar[] "in" parameter is modified in place. The warning would say "modifying string input parameter - possible violation of copy-on-write". They would then search around for copy-on-write in the doc and learn about the "right" way.

But how would one tell the lint that my code is intentionally *not* doing a copy-on-write? As in the ToUpperCase() example. // Modify in place - i.e. Not CoW. dchar[] ToUpperCase(dchar[] x) { foreach(inout dchar c; x) c = Upper(c); return x; } // Return a new modified string - i.e. CoW dchar[] ToUpperCase(dchar[] x) { dchar[] y; y.length = x.length; foreach(int i, inout dchar c; x) y[i] = Upper(c); return y; } -- Derek Parnell Melbourne, Australia 11/03/2005 11:49:35 PM
Mar 11 2005
next sibling parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Derek Parnell" <derek psych.ward> wrote in message 
news:1scvmsoj94p35$.1jlrqgw7ijhz2.dlg 40tude.net...
 On Fri, 11 Mar 2005 07:48:55 -0500, Ben Hinkle wrote:

 [snip]
 However, because one can never be certain that the routine writer has 
 used
 this idiom, it is 'safer' to pass a reference to a copy of the data
 instead
 of a reference to the original data.

 It would be nice if we could get the compiler to help us error prone
 coders. If would just tell the compiler that my intention is to *not*
 change some referred-to data, then the compiler could alert me to code
 that
 actually is known to change the data. This alone would be a great 
 advance
 in being able to express the coder's intentions and thus reduce mistakes
 in
 source code.

The compiler/lint can give a warning when a char[], wchar[] or dchar[] "in" parameter is modified in place. The warning would say "modifying string input parameter - possible violation of copy-on-write". They would then search around for copy-on-write in the doc and learn about the "right" way.

But how would one tell the lint that my code is intentionally *not* doing a copy-on-write? As in the ToUpperCase() example.

That's why it's a warning - and given that the standard is cow it would be odd to write a large number of functions that violate cow since users who expect cow (like me) would get confused about how to use those functions. One could also mark the input to ToUpperCase as inout, which would have the effect of forcing it to be an lvalue but has the benefit of informing users and the compiler/lint of the intention.
Mar 11 2005
prev sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Derek Parnell wrote:

 But how would one tell the lint that my code is intentionally *not* doing a
 copy-on-write?

If "readonly" is the default for arrays, then we would need some kind of keyword telling that the array in question would be modified in place. One suggestion that came up was to use the "in" and "out" keywords, as in: "dchar[in]" (which would be the default) and "dchar[inout]" In C and C++, there in-place read-write is the default and you use the oddly named "const" keyword to tell that it's a read-only: const char* It could be made to work similar in D, just make read-only the default ? Easier than changing everything else to use "readonly char[]" arguments. It would also make Object.toString() make more sense, as it would return a readonly string and not a writable buffer tino the objects innards...
 As in the ToUpperCase() example.
 
 // Modify in place - i.e. Not CoW.
 dchar[] ToUpperCase(dchar[] x)
 {
     foreach(inout dchar c; x)
         c = Upper(c);
 
     return x;
 }

This could use some keyword telling that it will *not* follow the standard idiom of using copy-on-write, but will modify in place... (which would also mean that it would segfault if passed a literal!) Something like: dchar[] ToUpperCase(dchar[inout] x); or dchar[] ToUpperCase(readwrite dchar[] x); Placing "out" before the array: dchar[] ToUpperCase(out dchar[] x); Just means that you will modify the *slice* (i.e. like length or ptr), not that you mean to change the actual characters that it points to... (the very ones it was currently pointing to on function entry, that is) Examples: void read(out char[] s); This means that it will read from the stread into a new buffer, and then return a slice to this buffer. But *not* that it will change the characters that s was pointing to, when the function was called.
 // Return a new modified string - i.e. CoW
 dchar[] ToUpperCase(dchar[] x)
 {
     dchar[] y;
     y.length = x.length;
     foreach(int i, inout dchar c; x)
         y[i] = Upper(c);
 
     return y;
 }

You might want to look at std.string.toupper, for the default routine ? (taking the default string type, char[], as a Copy-on-Write argument, and optimized both for ASCII strings and for "already uppercase" too) --anders
Mar 11 2005