July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7j26$dkb$1@digitaldaemon.com...
> const is not a physical protection. And never was.
> It is logical declaration of intention:
>
>      I am not going to change this parameter or
>      value it is refereing, so, compiler, please,
>      warn me if I'll do this accidentally.

Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason.

A const thing that instead, is a guarantee that the underlying values won't change, is actually useful. An optimizer can do a lot with it.


July 03, 2005
"Ben Hinkle" <ben.hinkle@gmail.com> wrote in message news:da7mmr$fjl$1@digitaldaemon.com...
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7i52$cv9$1@digitaldaemon.com...
>>
>> "Ben Hinkle" <ben.hinkle@gmail.com> wrote in message news:da7fo5$bje$1@digitaldaemon.com...
>>>
>>> "Walter" <newshound@digitalmars.com> wrote in message news:da6k71$11rs$1@digitaldaemon.com...
>>>>
>>>> "Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:da4afr$24jc$1@digitaldaemon.com...
>>>>> How would this cover the following case that Walter's proposal covers:
>>>>> class A { int x; }
>>>>> void foo(in A obj){
>>>>>   int y = obj.x;
>>>>>   // do whatever you want...
>>>>>   assert( obj.x == y );
>>>>> }
>>>>> void main() {
>>>>>   A obj = new A;
>>>>>   foo(obj); // says it doesn't change obj
>>>>> }
>>>>> Is it practical to force A to implement some immutability just because
>>>>> foo
>>>>> doesn't change its inputs? I'm not saying Walter's proposal is
>>>>> prefect.
>>>> It's
>>>>> very strong for foo to say no other thread or reference will change
>>>>> obj
>>>>> since it has no control over what other threads are doing. I would be
>>>> taking
>>>>> pretty much blind leap of faith when declaring an object reference as
>>>>> 'in'
>>>>> and saying that no other thread is stepping on that object during the
>>>>> call
>>>>> lifetime.
>>>>
>>>> You're right. I have misgivings about it for that reason.
>>>>
>>>> On the other hand, look at C++ "const". Nothing about "const" says that
>>>> some
>>>> other thread or reference cannot change the value out from under you at
>>>> any
>>>> moment. Furthermore, it can be cast away and modified anyway. The
>>>> semantic
>>>> value of C++ "const" is essentially zip. This is why I am often
>>>> flummoxed
>>>> why it is given such weight in C++.
>>>
>>> Personally I'm also surprised people are so paranoid in D about possible
>>> COW violations. What's the phrase from Spiderman ... "with great power
>>> comes great responsibility" :-)
>>> It's funny that Java and C# don't have const and people seem to survive.
>>> Granted in Java people IMO overcompensate by dup'ing too often so I hope
>>> D users don't go that route.
>>
>> "Java and C# don't have const"
>>
>> Umm...
>>
>> Java has 'final' keyword. You define an entity once and cannot change it or derive from it later. More specifically: a final class cannot be subclassed, a final method cannot be overridden and a final variable cannot change from its initialized value. Function parameters can also be declared as final.
>
> Currently D's final is more limited than Java's but I have always assumed D's final will eventually match Java's. It still isn't the same as C++'s const, though.

Yes, Java::final is not a C::const (it cannot protect references).

Java::final is exactly D::const now except of Java::final can be used in function parameters declaration and D's counterpart - cannot.

I have no idea of what D::final means. It is
defined as a keyword but have no meaning so far, AFAIK.
(correct me.)


>
>> C# has 'readonly' keyword. It can be used in declaration of class fields
>> and in declaration of function parameters.
>> C# has also const keyword which is pretty much D keyword except of
>> C#::const is protecting also references. E.g. you cannot
>> say "hello"[0] = 'b';
>
> Sure, but this, too, isn't const. D has getters and setters so one can make readonly properties. I know about C#'s const vaguely but I'm not sure what you mean by "is protecting also references". The example you give is of a string but strings are immutable and are independent of C#'s const keyword as far as I know. How does one make a non-string reference const?

Mea culpa, C# example and my statement about it is terribly wrong.
C# cannot implement 'const correctnes'
( http://en.wikipedia.org/wiki/Const_correctness )
too. Neither do Java.

But they do have immutable strings, you are right higlighting this.


>
>> And more regarding strings in these systems:
>>
>> Java/.NET String "package" consist of
>>
>> 1) String class (immutable) and
>> 2) StringBuffer (mutable) class
>>
>> Literal strings there are instances of String class
>> which is immutable, sic!
>
> Immutable strings is really the only place where D diverges from Java/C#. It's also probably the most common use of const in C++. To me that isn't enough reason to introduce const, though.

std.openrj.d:

class Record
{
    Field[] fields()
    {
        return m_fields.dup;
    }
}

Do you like this dup?

class Field
{
    final char[]  name()
    {
        return m_name;
    }
}

Pay attention that
std.openrj is an attempt to create
OOP, reusable, effective and robust library module in D.
Lack of constness is seen in each class of it.

>
>> I would like to highlight this again:
>>
>> In modern programming systems string implementation is a bundle
>> of friendly value classes (immutable) and buffer (mutable) classes.
>>
>> D currently has only StringBuffer (sort of).
>>
>> Only char#[] and char[] *together* can be considered as "string in D" by C++, Java or C# programmers.
>
> Why bother with multiple types/classes when D already spanks the competition with one? We should keep things as simple as possible.

Agreed in principle, but
"simple as possible" does not mean "sancta simplicitas", right?

"I'll give you my slice and don't forget to dup it as it is not yours."
This does not work in serious programming as
slice creation happens in one place and its consuming
in galaxy far far away and code of three developers
happens in between. It is EXTREMELY difficult to debug.
I know. It happened to me once in Harmonia and I wasted
almost three days to catch it. Sigh...
And I was designing it by myself - not even in team...

Andrew.


July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7jil$dsm$1@digitaldaemon.com...
> One more:
>
> Java, C#, C, C++ and Pascal (Delphi)
> has concept of const (parameters and references)
> and these are the most popular languages so far.

Java only has top level const (final). Any data referred to by a final reference can be changed through that reference (or any other reference to the same object). About the only value it has other than simple constant folding (as pointed out by Matthew) is that any uninitialized finals must be initialized exactly once in the constructors.

As far as preventing a function from modifying the fields of a 'final' reference parameter, it is useless.


July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7s6r$jcd$1@digitaldaemon.com...
> "I'll give you my slice and don't forget to dup it as it is not yours."
> This does not work in serious programming as
> slice creation happens in one place and its consuming
> in galaxy far far away and code of three developers
> happens in between. It is EXTREMELY difficult to debug.
> I know. It happened to me once in Harmonia and I wasted
> almost three days to catch it. Sigh...
> And I was designing it by myself - not even in team...

The COW rule for when to .dup is:

    When you're going to change the data, and you're not *sure* you're the
sole handle to it.

I don't see why the need is there for m_fields.dup in openrj.d. Preemptively duping something by the provider is the wrong approach to COW. Duping should be done by the consumer of it, and then only if the consumer modifies it.


July 03, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:da7pp5$i06$1@digitaldaemon.com...
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7j26$dkb$1@digitaldaemon.com...
>> const is not a physical protection. And never was.
>> It is logical declaration of intention:
>>
>>      I am not going to change this parameter or
>>      value it is refereing, so, compiler, please,
>>      warn me if I'll do this accidentally.
>
> Yet the value can change anyway. Another reference can change it, and
> another thread can change it. It isn't "constant" at all, and cannot be
> relied on to be constant, even if your program is 100% "const-correct".
> The
> C++ const is *completely useless* to the compiler optimizer for that
> reason.

Right!

Let's throw out private, protected, etc. As they are:
(here goes citation of your statement above)

Who the hell started this 'canard' (hoax, fr.) that const is
for compiler optimization?

const is a basic of DbC. It is a contrct. Not more not less.

const references allows to mininimize needless memory
allocations in design. This is true. And this is how 'const'
helps optimization. Best optimizer is you and me
- not a compiler.

Table at bottom of http://www.terrainformatica.com/htmlayout/ It is not about const but const was a significant part of it.

>
> A const thing that instead, is a guarantee that the underlying values
> won't
> change, is actually useful. An optimizer can do a lot with it.
>

ooohh... could you first provide me an option to *declare* e.g. slice as immutable thus I'll be able to return it from function without duping it? *That* would be optimization.

Walter, again, what language are you going to substitute
by D? What is the main target? C/C++?
If yes then they have const references.
If Java or C# then show how to implement String in D
and very desireable with slices - they are extremely useful
and are making D so attractive (among other good and
useful features).

Again, in my opinion
1) const references - const arrays and pointers
2) opAssign/dtors in structures
are the *only* things left in D not-implemented from
C++ feature set. If they will be there you and anyone
can honestly say "D is next letter after C and C++" as
it allows you to do *everything* that you can in C++
and it has much more "well done" features - true next step.

Andrew.








July 03, 2005
Hi Walter,

>> const is not a physical protection. And never was.
>> It is logical declaration of intention:
>>
>>      I am not going to change this parameter or
>>      value it is refereing, so, compiler, please,
>>      warn me if I'll do this accidentally.
>
>Yet the value can change anyway. Another reference can change it, and another thread can change it. It isn't "constant" at all, and cannot be relied on to be constant, even if your program is 100% "const-correct". The C++ const is *completely useless* to the compiler optimizer for that reason.

I can't fathom that the compiler can't make use of the fact that you are telling it: "The following function body will not modify [variable] at all, ever."?

Surely this is useful information that can be made into some kind of optimization, specially when ignoring the dangers of threading: I simply don't see why threads even have to come into the picture. You could take a soldering iron and hack memory directly and the runtime won't be able to protect against that. But does it matter?

I don't think that's the point of const. It is not a guarantee by the _compiler_ that the value will remain constant. It is a guarantee by the _programmer_ that his function body will not touch the variable. Of course, the compiler (or lexer), should make sure to prevent the programmer from violating his contract via syntax.

>A const thing that instead, is a guarantee that the underlying values won't change, is actually useful. An optimizer can do a lot with it.

But wouldn't such a thing (a runtime-enforced const) cause big performance problems? It would mean the runtime would have to deal with race conditions and thread synchronization for every single const variable and object in memory. That seems awfully slow to me; a gratuitous use of locks and mutexes.

If so, this makes for an interesting catch-22. If you implement it, you can optimize, but you get the performance penalty. If you don't implement it, there's no performance penalty, but you can't optimize either.

I say forget about the runtime-const. Stick with semantic (compile-time) const, and try to make use of that info to optimize. Forget about threading too, which should make it easier. If the programmer wants to make sure some variable won't change via some other thread, then he should:

[a] simply not use it in that thread; or
[b] make the function that uses it on that thread take a const; or
[c] lock and synchronize it himself individually.

As far as references go, you should not (syntactically) be able to make a non-const reference to a const. That should guarantee correctness within the function body. Examples:

# void func(const type[] c_param) {
#    assert(c_param.length);
#
#    const type[] c_array = c_param;    // OK.
#    const type   c_item  = c_param[0]; // OK.
#    type[]       n_array = c_param;    // FAILS.
#    type         n_item  = c_param[0]; // FAILS.
#
#    // And so forth:
#    const type[] a = c_array;    // OK.
#    const type   b = c_array[0]; // OK.
#    const type   c = c_item;     // OK.
#    type[]       d = c_array;    // FAILS.
#    type         e = c_array[0]; // FAILS.
#    type         f = c_item;     // FAILS.
#
#    // Same thing for slicing.
#    const type[] g = c_param[0 .. $]; // OK.
#    const type[] h = c_array[0 .. $]; // OK.
#    type[]       i = c_param[0 .. $]; // FAILS.
#    type[]       j = c_array[0 .. $]; // FAILS.
# }

Pretty simple, if you ask me. You could make "in" = "const" (syntactically) in that sense, which should have always been the default.

Or you could do:
- No modifier: e.g. func(int a)    : This means make a (mutable, independent)
copy of the caller's variable. Use dup for arrays, etc.
- IN modifier: e.g. func(in int a) : This means const as defined above.

Cheers,
--AJG.


July 03, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:da7u7k$kkh$1@digitaldaemon.com...
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7s6r$jcd$1@digitaldaemon.com...
>> "I'll give you my slice and don't forget to dup it as it is not yours."
>> This does not work in serious programming as
>> slice creation happens in one place and its consuming
>> in galaxy far far away and code of three developers
>> happens in between. It is EXTREMELY difficult to debug.
>> I know. It happened to me once in Harmonia and I wasted
>> almost three days to catch it. Sigh...
>> And I was designing it by myself - not even in team...
>
> The COW rule for when to .dup is:
>
>    When you're going to change the data, and you're not *sure* you're the
> sole handle to it.

In real projects and in real life this *not sure* is almost always.

>
> I don't see why the need is there for m_fields.dup in openrj.d.
> Preemptively
> duping something by the provider is the wrong approach to COW. Duping
> should
> be done by the consumer of it, and then only if the consumer modifies it.
>

I know this theory.

The whole team are C++ programmers. They get used to const.
And you know.... this is really a "code culture" thing -
respect of developers who are working with you and using
your code.
const - it is mine - don't touch it. no const - it is yours.
And C++ compiler helps us a lot here to prevent stupid mistakes.

All most respectfull C++ guys are unified in 'const is good''
http://artima.com/intv/const.html
Shall I tell my team that const is wrong because:
"it is useless for optimizing"?
I'll never will do that, sorry.

pointers are so effective but dangerous. without const they are dangerous in order of magnitude. The same apply to D slices.

Andrew.
















July 03, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:da7t1t$jth$1@digitaldaemon.com...
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7jil$dsm$1@digitaldaemon.com...
>> One more:
>>
>> Java, C#, C, C++ and Pascal (Delphi)
>> has concept of const (parameters and references)
>> and these are the most popular languages so far.
>
> Java only has top level const (final). Any data referred to by a final
> reference can be changed through that reference (or any other reference to
> the same object). About the only value it has other than simple constant
> folding (as pointed out by Matthew) is that any uninitialized finals must
> be
> initialized exactly once in the constructors.
>
> As far as preventing a function from modifying the fields of a 'final' reference parameter, it is useless.
>

Mea culpa. Was too optimistic about Java/C# .

Working horses C, C++, Delphi still there though.



July 03, 2005
"AJG" <AJG_member@pathlink.com> wrote in message news:da7vvd$lm6$1@digitaldaemon.com...
> Hi Walter,
>
>>> const is not a physical protection. And never was.
>>> It is logical declaration of intention:
>>>
>>>      I am not going to change this parameter or
>>>      value it is refereing, so, compiler, please,
>>>      warn me if I'll do this accidentally.
>>
>>Yet the value can change anyway. Another reference can change it, and
>>another thread can change it. It isn't "constant" at all, and cannot be
>>relied on to be constant, even if your program is 100% "const-correct".
>>The
>>C++ const is *completely useless* to the compiler optimizer for that
>>reason.
>
> I can't fathom that the compiler can't make use of the fact that you are
> telling
> it: "The following function body will not modify [variable] at all,
> ever."?
>
> Surely this is useful information that can be made into some kind of
> optimization, specially when ignoring the dangers of threading: I simply
> don't
> see why threads even have to come into the picture. You could take a
> soldering
> iron and hack memory directly and the runtime won't be able to protect
> against
> that. But does it matter?
>
> I don't think that's the point of const. It is not a guarantee by the
> _compiler_
> that the value will remain constant. It is a guarantee by the _programmer_
> that
> his function body will not touch the variable. Of course, the compiler (or
> lexer), should make sure to prevent the programmer from violating his
> contract
> via syntax.
>
>>A const thing that instead, is a guarantee that the underlying values
>>won't
>>change, is actually useful. An optimizer can do a lot with it.
>
> But wouldn't such a thing (a runtime-enforced const) cause big performance
> problems? It would mean the runtime would have to deal with race
> conditions and
> thread synchronization for every single const variable and object in
> memory.
> That seems awfully slow to me; a gratuitous use of locks and mutexes.
>
> If so, this makes for an interesting catch-22. If you implement it, you
> can
> optimize, but you get the performance penalty. If you don't implement it,
> there's no performance penalty, but you can't optimize either.
>
> I say forget about the runtime-const. Stick with semantic (compile-time)
> const,
> and try to make use of that info to optimize. Forget about threading too,
> which
> should make it easier. If the programmer wants to make sure some variable
> won't
> change via some other thread, then he should:
>
> [a] simply not use it in that thread; or
> [b] make the function that uses it on that thread take a const; or
> [c] lock and synchronize it himself individually.
>
> As far as references go, you should not (syntactically) be able to make a
> non-const reference to a const. That should guarantee correctness within
> the
> function body. Examples:
>
> # void func(const type[] c_param) {
> #    assert(c_param.length);
> #
> #    const type[] c_array = c_param;    // OK.
> #    const type   c_item  = c_param[0]; // OK.
> #    type[]       n_array = c_param;    // FAILS.
> #    type         n_item  = c_param[0]; // FAILS.
> #
> #    // And so forth:
> #    const type[] a = c_array;    // OK.
> #    const type   b = c_array[0]; // OK.
> #    const type   c = c_item;     // OK.
> #    type[]       d = c_array;    // FAILS.
> #    type         e = c_array[0]; // FAILS.
> #    type         f = c_item;     // FAILS.
> #
> #    // Same thing for slicing.
> #    const type[] g = c_param[0 .. $]; // OK.
> #    const type[] h = c_array[0 .. $]; // OK.
> #    type[]       i = c_param[0 .. $]; // FAILS.
> #    type[]       j = c_array[0 .. $]; // FAILS.
> # }
>
> Pretty simple, if you ask me. You could make "in" = "const"
> (syntactically) in
> that sense, which should have always been the default.
>
> Or you could do:
> - No modifier: e.g. func(int a)    : This means make a (mutable,
> independent)
> copy of the caller's variable. Use dup for arrays, etc.
> - IN modifier: e.g. func(in int a) : This means const as defined above.
>

Thanks, AJG, excellent statement.

Except final :)

in, inout and out in function parameters defines direction. This quite
different
from const and let's don't mix it.

See, declaration:

void toLower(in char[] str)

means that toLower function will not change length of the str but allowed to
change its content.
Reasonable? Yes.

Next step, this declaration:

char[] toLower(in const char[] str)

means that: 1) this toLower will not change str. nor length nor its content.
2) It returns mutable array and caller is free to use it in the way it
wants -
it may own it, store it, whatever.

These two functions will peacefuly coexist in phobos as they have different signatures. Developer can do *optimal* choice.

Signature:

const char[] getDir(in const char[] path)

means: getDir will not do anything with path - will just return const slice.

Signature:

void splitPath(in const char[] path,
                    out const char[] dir,
                    out const char[] filename,
                    out const char[] ext)

Means it will not touch path and will return constant slices representing path parts.

Signature:

void splitPath(in const char[] path,
                    out char[] dir,
                    out char[] filename,
                    out char[] ext)

Means it will not touch path and will return arrays
- copies of path parts - caller is free to own them.

Anyone brave here to tell me (us with AJG :) that all this above have nothing common with optimization?

























July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da818n$md2$1@digitaldaemon.com...
>
> "Walter" <newshound@digitalmars.com> wrote in message news:da7u7k$kkh$1@digitaldaemon.com...
> >
> > "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da7s6r$jcd$1@digitaldaemon.com...
> >> "I'll give you my slice and don't forget to dup it as it is not yours."
> >> This does not work in serious programming as
> >> slice creation happens in one place and its consuming
> >> in galaxy far far away and code of three developers
> >> happens in between. It is EXTREMELY difficult to debug.
> >> I know. It happened to me once in Harmonia and I wasted
> >> almost three days to catch it. Sigh...
> >> And I was designing it by myself - not even in team...
> >
> > The COW rule for when to .dup is:
> >
> >    When you're going to change the data, and you're not *sure* you're
the
> > sole handle to it.
>
> In real projects and in real life this *not sure* is almost always.

True, but it's also true that most of the time, one doesn't care because one has no need to modify the data.

> > I don't see why the need is there for m_fields.dup in openrj.d.
> > Preemptively
> > duping something by the provider is the wrong approach to COW. Duping
> > should
> > be done by the consumer of it, and then only if the consumer modifies
it.
>
> I know this theory.
>
> The whole team are C++ programmers. They get used to const.
> And you know.... this is really a "code culture" thing -
> respect of developers who are working with you and using
> your code.
> const - it is mine - don't touch it. no const - it is yours.
> And C++ compiler helps us a lot here to prevent stupid mistakes.
>
> All most respectfull C++ guys are unified in 'const is good''
> http://artima.com/intv/const.html
> Shall I tell my team that const is wrong because:
> "it is useless for optimizing"?
> I'll never will do that, sorry.

C++ const benefits are greater than zero, even though it is useless to the optimizer as it gives no meaningful semantic information.

> pointers are so effective but dangerous. without const they are dangerous in order of magnitude. The same apply to D slices.

I find it curious that many features of C++ have leaked out into other languages, but not const.

I agree with you that C++ has a culture of "const is good".

I'd like to find something better, something that works (i.e. that gives useful semantic information).

I also am not understanding how const would help with COW mistakes.