July 03, 2005
Andrew Fedoniouk wrote:

>>But for C/C++ there is "const" - D needs something similar, but better.
> 
> D already has better part - in, inout, out.
> These combined with const *is* better from notational point of view
> than in current C/C++.

The only problem being that in/out just affects the pointer/array ref,
where it works fine already, but not the actual contents of the array...

In some ways, that is similar to how passing an object reference to
a function allows it to change internal state of the object passed.

But the difference is of course that the object is changed through
methods while the array passed could be modified "behind your back".


So we still need some "mutable" attribute to give to strings/arrays,
and something like "char[out] string" might work - but is rather ugly ?

Must confess that I find the proposed char#[] syntax to be obscure too,
and would rather have both "mutable char[]" (as well as "static if"...)

Assuming here that C++-style "const" is the default for a parameter,
and that it would be more useful to have a keyword for the opposite.


But I think that it's a _very_ good chance that this ends up like the
booleans, with some syntax approaching the real thing but not enforced.

How it is *supposed* to work is pretty clear from the Copy-on-Write ?
It's just that there is not too much "checking" from the D compiler...

For me it's not really a show-stopper, just a(nother) small annoyance.
The string handling in D still rocks when compared to what old C had.

--anders
July 03, 2005
>> 2) 'In' does not allow to distinguish cases:
>>
>> void toUpper(in char[] str_in_place);
>> char[] toUpper(in const char[] str);
>>
>> and select optimal implementation.
>
> That's correct, there would be no overloading based on const-ness. I know
> this is commonplace in C++, but frankly I think it's poor design. A
> function
> overloaded on const implicitly has significantly different behavior, and
> so
> should have a different name.

Perhaps dstyle.html should say functions with a leading 'to' should not modify their inputs. There are several toFoo functions in phobos and it would be nice to keep that style consistent.


July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da97g2$1l30$1@digitaldaemon.com...
>
> "Walter" <newshound@digitalmars.com> wrote in message news:da888e$rhs$1@digitaldaemon.com...
> >
> > "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.
>
> Absolutely true. This is why e.g. string literals
> shall have type const char[] and not just a char[] by default.
> This is stupid design mistake in C++:
> "hello"[0] = 0;
> will compile and run on one machines and will not on others.

It is an error in C++ to do that, though it is allowed by some compilers for backwards compatibility. In C++, string literals are const char*.

> Walter, need of const appears together with raw pointers. It is critical to have pointers (slices included) together with const.
>
> If some language takes ++ from C but not pointers then
> it does not need const so much.
>
> There is no language in active use which has raw pointers and has no concept of pointers to const data.

I don't know of any language that even allows raw pointers other than C, C++ and D!

> > 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.
>
> What are the "COW mistakes"? I don't understand this exactly....

A COW mistake would be, for example, modifying a reference when you aren't sure you're the owner of it.

> Anyway....
>
> void  toLower(in char[] str)
> char[]  toLower(in const char[] str)
>
>
> Having them both is a matter of optimization.
> First does transformation in place, second allocates
> new string.
>
> Do these two together make sense? Definitely, yes.

See my comments on this example in another post here.


July 03, 2005
"Ben Hinkle" <ben.hinkle@gmail.com> wrote in message news:da9b6j$1ouo$1@digitaldaemon.com...
> Perhaps dstyle.html should say functions with a leading 'to' should not modify their inputs. There are several toFoo functions in phobos and it would be nice to keep that style consistent.

That's a good idea. There are also the 'is' prefix functions.


July 03, 2005
In article <da7pp5$i06$1@digitaldaemon.com>, Walter says...
>
>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".

That is true, but also in fact completly irrelevant. I think you might have misunderstood the intention of the const keyword in C++. It's not meant to be, and has never been meant to be, a guarantee to the internals of the function that "this value will not change". It's not supposed to protect the INSIDE of the function from the outside world, but quite the opposite. It's a guarantee (or contract, if you will) with the code OUTSIDE the function (ie. the caller) that "THIS function will never change this value." What happens in other threads and other references has no relevance to this contract. Also, your example with foo(a,a) is ok, since when you (the caller) send 'a' as the second (non-const) parameter, the function is 'allowed' to change it. Thus the function has not broken the contract.

I am not arguing for or against const in D here. My experience with it in C++ has been pretty much the same as yours, and so I am not really convinced of it's usefulness. But your argument really attacks a use of 'const' that was never intended, and thus is not a very good argument.

Nick


July 03, 2005
"Dave" <Dave_member@pathlink.com> wrote in message news:da95on$1jff$1@digitaldaemon.com...
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da93ap$1g54$1@digitaldaemon.com...
>>
>> "Walter" <newshound@digitalmars.com> wrote in message news:da88rb$ruj$1@digitaldaemon.com...
>>>
>>> "AJG" <AJG_member@pathlink.com> wrote in message news:da7vvd$lm6$1@digitaldaemon.com...
>>>> >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."?
>>>
>>> Consider the following C++ function:
>>>
>>>    int foo(const int *p, int *q)
>>>    {
>>>        int i = *p;
>>>        *q = 3;
>>>        return *p;
>>>    }
>>>
>>> At the return statement, could we replace *p with i, thereby saving ourselves a dereference operation? After all, p points to "const" data, right? Wrong. Consider calling foo() this way:
>>>
>>>    int a[3];
>>>    ...
>>>    foo(a, a);
>>>
>>> Since p and q now hold the same value, *q = 3; will change the contents
>>> of
>>> what p points to.
>>>
>>> This code is perfectly legal C++, and is "const-correct". It happens
>>> often
>>> enough in real code, too, as I discovered when trying to implement this
>>> optimization.
>>
>> Walter, it is enough for me to know that
>>
>> int foo(const int *p, int *q)
>>   {
>>       int i = *p;
>>       *q = 3;
>>
>>       .... 200 lines of code
>>
>>       return *p;
>>   }
>>
>> will not change *p. I am not asking for optimization here. Optimization happened before - when I wrote this fucntion declaration using const parameters.
>>
>
> The whole problem is, with the C++ rules, the optimizations cannot even be done by the code generator - you may think you've optimized something with const, but in reality the code generator cannot make use of it because of how const is implimented in C++ and the compiler cannot figure out 100% for certain what is being done with referenced data.

Again I am willing to write to functions which provided together will give an optimal choice:

void toUpper( in char[] strbuf ) // inplace
char[] toUpper( in const char[] str ) // return brand new.

I am free to chose optimal function for particular case.
And while implementing it compiler will not allow
me to change *accidentally* value of str.

This is *deterministic* optimization.
codegenerator *may* do optimization. And may not.
const is not about codegenerator optimiziation.
Dot. Forget about it.

>
>> I understand that you focused on optimiziation as compiler and
>> codegenerator
>> writer. This is perfectly good and thank you for that.
>>
>
> What I think Walter has in mind with his "explicit in" proposal for D is "constness" while still allowing for the optimizations that C++ can't do, or at least can't do without making the compiler much more complicated.
>
>> But const is a matter of language design and not about optimization. Well not exactly as if I will write both:
>>
>> int foo(const int *p, int *q)
>> int foo(int *p, int *q)
>>
>> then I will make an act of optimization on the design level.
>>
>> Again: from the point of optimization 'public', 'private' attributes are almost worthless.
>
> 'private' and 'package' data members may have some optimizations applied because of the protection attribute scope rules.
>
> private and package methods can't be virtual, so there are some optimizations having to do with inlining and the vtable that can be (and are) done by the compiler, because 'private' or 'package' guarantees that those are not virtual methods.

I think that you a wrong here as following:

import std.stdio;

class One
{
  package int foo() { return 1; }
}

class Two: One
{
  override package int foo() { return 2; }
}

int main()
{
 Two t = new Two;
 return t.foo();
}

compiles just fine.


>
>> But despite of that they are in the language. const is the same - it is a
>> contract.
>> Any argument that you can *intentionally* break constness are true.
>> The same apply to visibility attributes.
>>
>> Andrew.
>>
>>
>
> 


July 03, 2005
Hi Walter,

>> Once again, what if pointers are not considered, would this make things
>easier?
>> If you take out pointers, couldn't the compiler detect if you were sending
>the
>> same variable to multiple differently-accessable parameters?
>
>The compiler cannot detect it in the general case, as a function may receive a non-const reference to the same data by an arbitrarilly complex path.

I know I'm pushing it here, but can't the compiler follow that arbitrarily complex path (excluding pointers)?

>What you're suggesting is different from C++ "const" - you're suggesting that const actually mean "constant". This is definitely more interesting that C++ const, but then there's the problem of undefined behavior and trying to detect it.

Hm... perhaps. Ok, first let me see if I understand your point:

You say: C++ const, which is semantic only, is useless for optimizations.
You say: Implementing C++ const in D would be equally useless re: optimizations.
I say:   const should be _always_ about semantics ("correctness"), and _if
possible_ provide optimizations.
You say: That is not good enough, we need correctness and optimization.

Is that correct?

So, if you can solve the arbitrarily complex path problem, you get the both of both worlds, right? I dunno if this is possible, just thinking out loud.

If not syntactically, could it be done via whole-program static analysis?

Thanks,
--AJG.


July 03, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:da99t5$1net$1@digitaldaemon.com...
>
> "Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da95gq$1j4t$1@digitaldaemon.com...
>> 1) How in will solve this:
>>
>> class Record
>> {
>>     Field[] fields()
>>     {
>>         return m_fields.dup; // this is not needed, isn't it?
>>                                      // but it must be here in current D.
>>     }
>> }
>
> It won't, but then again, I don't see that the .dup is necessary there, as fields() is a producer of a value, not a consumer.
>
>> 2) 'In' does not allow to distinguish cases:
>>
>> void toUpper(in char[] str_in_place);
>> char[] toUpper(in const char[] str);
>>
>> and select optimal implementation.
>
> That's correct, there would be no overloading based on const-ness. I know
> this is commonplace in C++, but frankly I think it's poor design. A
> function
> overloaded on const implicitly has significantly different behavior, and
> so
> should have a different name.
>
>
>> > volatile/volatile in/volatile out/volatile inout - 'volatile',
>> > 'volatile
>> > in', 'volatile out' and 'volatile inout' params. would basically
>> > operate
>> > exactly as they do now. Just like other statements in any other scope,
>> > a
>> > "volatile" param. would mean "inhibit optimizations on the variable
>> > that
>> > may effect memory reads/writes". Not even a new keyword..
>> >
>> > The whole justification for these new defaults is because the cases
> where
>> > "volatile" would have to be used for the code to operate correctly are
>> > a
>> > small minority, so shouldn't the default go with what benefits the
>> > great
>> > majority of cases?
>> >
>> > Also, the same justification goes for making the default [none] and
>> > 'in'
>> > operate the same way w.r.t. the new proposal - majority of cases rules.
>> > Another big plus would be not having to litter code with 'in' (like C++
>> > code is littered with 'const').
>> >
>>
>> "littered with 'const'"....
>>
>> well, it depends.... If European will see Stone Garden in Japan he will find it littered by stones.
>>
>> For me personally code which is not using const looks non-prefessional and written by young hacker in 'fire-n-forget' mode. Non maintainable, non reliable, non optimized.
>>
>> Someone can tell that:
>>
>> private int something1
>> public int something2
>>
>> is littered with private and public.
>> Does it *really* mean that it is littered?
>
> The idea is that the most common case should be the default. Would you
> agree
> that for the vast majority of function parameters, they are read only?
> That
> mutable ones are relatively rare? If so, then it makes sense to have the
> uncommon ones need the extra syntax.
>

Walter, imagine that you know nothing about internals
of this function:

  char* toStringz(char[] string)

what you can tell about it?

And if you'll see

  char[] toStringz(const char[] string)

isn't it better? You don't need documentation or its source code in most cases.

> As for myself, since most parameters in C++ code are const, the const everywhere tends to visually clutter up the code, obscuring the other stuff.
>

most cases are strings I believe. So do

alias const char[] string;
alias char[] string_buffer;

and use this strings. Word 'string' has same number of characters as 'char[]'.

And forget about clutter.











July 03, 2005
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:da9g47$1tfc$1@digitaldaemon.com...
>
> "Dave" <Dave_member@pathlink.com> wrote in message news:da95on$1jff$1@digitaldaemon.com...
>>
>> The whole problem is, with the C++ rules, the optimizations cannot even be done by the code generator - you may think you've optimized something with const, but in reality the code generator cannot make use of it because of how const is implimented in C++ and the compiler cannot figure out 100% for certain what is being done with referenced data.
>
> Again I am willing to write to functions which provided together will give an optimal choice:
>
> void toUpper( in char[] strbuf ) // inplace
> char[] toUpper( in const char[] str ) // return brand new.
>

I understand - I think we're all looking for some way to implement "constness" in a way that is better, for at least the majority of cases, than how C++ does it. From Walter's earlier post, it appears that overloading based on some type of "const" storage modifier is not going to happen, so I'll take what I can get in this regard, especially if it helps compiler implementors do their job better because then I get better tools.

Walter wants D's "constness" to be taken as a semantic guarantee of some value, and I agree with him on that, because then it's of more value to both the compiler and someone debugging code (const the way it is in C++ can actually hide bugs). I also agree with the notion that C++ constness is a mess and that is one of the major reasons why I want D to succeed, so I don't have to deal with that as it is.

I take it you basically want C++ constness in D - I just have to disagree with that because that's one of the things I think needs to be done better.

> I am free to chose optimal function for particular case.
> And while implementing it compiler will not allow
> me to change *accidentally* value of str.
>
>>
>> private and package methods can't be virtual, so there are some optimizations having to do with inlining and the vtable that can be (and are) done by the compiler, because 'private' or 'package' guarantees that those are not virtual methods.
>
> I think that you a wrong here as following:
>
> import std.stdio;
>
> class One
> {
>  package int foo() { return 1; }
> }
>
> class Two: One
> {
>  override package int foo() { return 2; }
> }
>
> int main()
> {
> Two t = new Two;
> return t.foo();
> }
>
> compiles just fine.
>
>

Try this:

# dmd -version=_package pt.d
# ./pt
1
1

vs. this:

# dmd pt.d
# ./pt
2
1

;---
import std.stdio;

class One
{
version(_package)
  package int foo() { return 1; }
else
  public int foo() { return 1; }
}

class Two: One
{
version(_package)
  override package int foo() { return 2; }
else
  override public int foo() { return 2; }
}

void main()
{
 Two t = new Two;
 writefln((cast(One)t).foo());
 One o = new One;
 writefln("%d\n",(cast(One)o).foo());
}


July 03, 2005
"Walter" <newshound@digitalmars.com> wrote in message news:da9dc2$1r5s$2@digitaldaemon.com...
>
> "Ben Hinkle" <ben.hinkle@gmail.com> wrote in message news:da9b6j$1ouo$1@digitaldaemon.com...
>> Perhaps dstyle.html should say functions with a leading 'to' should not modify their inputs. There are several toFoo functions in phobos and it would be nice to keep that style consistent.
>
> That's a good idea. There are also the 'is' prefix functions.
>
>

I beleive that next will be a proposal to use 'c' as a first
char of parameter name and all this will end up with
Polish Notation and the like... Poor man type system to be short.

Gentlemen, array and immutable slice are two *distinct* types with their own set of operations. The same for pointers - immutable pointer cannot be dereferenced to l-value.

And please don't cover holes in type system by inventing naming conventions. This is not honest.

Andrew.