Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
On Tuesday, January 24, 2012 15:52:50 H. S. Teoh wrote:
> Hi all,
>
> I'm a bit confused by what 'const' means when used as part of a member function's signature:
>
> class A {
> int x;
>
> const int f1() { ... }
> int f2() const { ... }
> const(int) f3() { ... }
> }
>
> Is there a difference between f1 and f2? If not, which is the preferred syntax? If yes, what is the meaning of 'const' in either case?
>
> I tried various code inside f1 and f2, and it seems in both of them I can't change x, which appears to mean that 'const' in this case refers to immutability of the class object? Is this correct?
>
> What exactly does 'const' mean in f3? That the returned int cannot be modified?
>
> Confused by const syntax,
const on a return value means that the return value is const. const on a member function means that the invisible this argument is const (meaning that you can't call non-const member functions within that function or mutate any member variables). You can think of it like this
int f2() const
becomes
int f2(const A this)
Now, the confusing part is the fact that unlike C++, D allows you to put the const for making the function on the _left-hand_ side of the function (C++ only lets you put it on the right). This is to increase consistency between modifers (public, override, pure, etc.) - they _all_ can go on both the right and left (which is very unfortunate in the case of const and immutable IMHO). That means that const (and immutable) always modify the function rather than the return value unless you use parens.
So, while a C++ programmer expects that
int f2() const
means that f2 is const, they're likely to be surprised by the fact that in
const int f1()
it's the int that's const, not f1. It's only in the case of
const(int) f3()
that the return value is const. You could, however, have both
const(int) f4() const
in which case both the return value and the function are const.
Now, having a const return value is rather pointless in the case of int, since it's a value type and would juts be copied. It matters a great deal more with a pointer or referenc type. e.g.
const(int*) func()
or
ref const(int) func()
or in the case of your A class,
const(A) func()
In those cases, it protects the return value from being mutated, since there's actually something to protect from mutation given that the return value is not a value type.
Hopefully, that clears things up.
- Jonathan M Davis
|
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 01/24/2012 04:06 PM, Jonathan M Davis wrote: >> class A { >> int x; >> >> const int f1() { ... } >> int f2() const { ... } >> const(int) f3() { ... } >> } >> [...] > int f2() const > > becomes > > int f2(const A this) > > Now, the confusing part is the fact that unlike C++, D allows you to put the > const for making the function on the _left-hand_ side of the function (C++ > only lets you put it on the right). Ok. > So, while a C++ programmer expects that > > int f2() const > > means that f2 is const, they're likely to be surprised by the fact that in > > const int f1() > > it's the int that's const, not f1. Have you phrased that last bit correctly? :) It seems to conflict with what you have said earlier. f1() and f2() are the same thing in D. Ali |
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
On Tue, Jan 24, 2012 at 07:06:47PM -0500, Jonathan M Davis wrote: [...] > So, while a C++ programmer expects that > > int f2() const > > means that f2 is const, they're likely to be surprised by the fact that in > > const int f1() > > it's the int that's const, not f1. [...] Wait, I thought 'const int f1()' means that 'int f1(const this, ...)', not the other way round? I guess you're trying to say that in C++: const int f(); means the return value is 'const int', but in D: const int f(); means the same thing as 'int f() const', and the return value is 'int'. Is that correct? // Anyway, I find this variable syntax a bit annoying. The basic syntax of a function is: <return type> <func_name>(<args...>) { <body> } But now we have additional modifiers like 'pure', 'lazy', 'const', etc., and syntax becomes: <modifiers> <return type> <func_name>(<args...>) <more_modifiers> { <body> } Which makes sense, since then you can write 'pure int f()' which reads nicely. However, in the case of const, it's very confusing because you're used to writing 'const <typename>' to mean 'const(<typename>)', yet here 'const int f()' means 'const(int f())' rather than 'const(int) f()': class A { const int f(); } auto a = new A; const int x; // typeof(x) == const(int) auto y = a.f(); // typeof(y) == int This is a visual ambiguity with the basic pattern '<return type> <func_name>(...)', which I find very jarring. Should I file an issue for this? :) T -- I think Debian's doing something wrong, `apt-get install pesticide', doesn't seem to remove the bugs on my system! -- Mike Dresser |
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan M Davis:
> Now, the confusing part is the fact that unlike C++, D allows you to put the const for making the function on the _left-hand_ side of the function (C++ only lets you put it on the right). This is to increase consistency between modifers (public, override, pure, etc.) - they _all_ can go on both the right and left (which is very unfortunate in the case of const and immutable IMHO). That means that const (and immutable) always modify the function rather than the return value unless you use parens.
Some time ago we have discussed this topic in an enhancement request in Bugzilla. The idea was to disallow code like:
struct Foo {
int x;
const const(int) bar() {
return 0;
}
}
void main() {}
and require the struct "const", "immutable" to be only on the right if present.
Walter shot this idea down for consistency. But I generally don't want consistency when it's just a potential source of confusion for the programmer :-)
Bye,
bearophile
|
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
On Tuesday, January 24, 2012 16:55:16 H. S. Teoh wrote: > On Tue, Jan 24, 2012 at 07:06:47PM -0500, Jonathan M Davis wrote: [...] > > > So, while a C++ programmer expects that > > > > int f2() const > > > > means that f2 is const, they're likely to be surprised by the fact that in > > > > const int f1() > > > > it's the int that's const, not f1. > > [...] > > Wait, I thought 'const int f1()' means that 'int f1(const this, ...)', > not the other way round? It does. I mis-typed. Sorry. > I guess you're trying to say that in C++: > > const int f(); > > means the return value is 'const int', but in D: > > const int f(); > > means the same thing as 'int f() const', and the return value is 'int'. > Is that correct? Yes. In C++, const must go on the right if it's going to modify the function rather than the return type. > // > > Anyway, I find this variable syntax a bit annoying. The basic syntax of a function is: > > <return type> <func_name>(<args...>) { <body> } > > But now we have additional modifiers like 'pure', 'lazy', 'const', etc., and syntax becomes: > > <modifiers> <return type> <func_name>(<args...>) <more_modifiers> { <body> > } > > Which makes sense, since then you can write 'pure int f()' which reads > nicely. However, in the case of const, it's very confusing because > you're used to writing 'const <typename>' to mean 'const(<typename>)', > yet here 'const int f()' means 'const(int f())' rather than 'const(int) > f()': > > class A { > const int f(); > } > auto a = new A; > const int x; // typeof(x) == const(int) > auto y = a.f(); // typeof(y) == int > > This is a visual ambiguity with the basic pattern '<return type> <func_name>(...)', which I find very jarring. > > Should I file an issue for this? :) There's nothing to file. It's been discussed before, and Walter shot down any changes. Attributes can go on either the right-hand side or the left-hand side of a function. In general, this is a complete non-issue. The problem is the ambiguity of const int f() where most people expect that to mean that the int is const, not the function. The proposed solution is to require that const be on the right (as in C++), but Walter insists on allowing const on the left for consistency's sake (since all of the other modifiers can go on both sides). immutable and shared have the same problem. But none of the other modifiers can apply to both variables and functions, so they aren't an issue. Having attributes on both sides is an artifact of borrowing from both C++ and C#/Java. The only modifiers on functions which exists in C++ are static and const; static goes on the left (but it can't affect return types), and const is always on the right. C# and Java, on the other hand, put all of their modifiers on the left, and none of those modifiers can apply to return types (they don't have const). So, requiring that all of the modifiers go on the left would conflict with C++ (and cause the issue that we currently have with const), and requiring that they all go on the right would be too weird for the Java and C# folks. So, we ended up with both. All in all, I don't think that it's an issue, except for const, immutable, and shared, in which case, it's a big issue, but Walter refuses to change it. In general, I'd argue that it's best practice to always put const, shared, and immutable on the right-hand side of the function to avoid this problem. I would consider any function which has them on the left-hand side without parens to be a likely bug. As for the rest, you can put them where you like. Personally, I put pure, nothrow, @safe, @trusted, and @safe on the right and put all of the others (i.e. the ones from other languages) on the left. - Jonathan M Davis |
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Tue, Jan 24, 2012 at 08:01:41PM -0500, bearophile wrote: > Jonathan M Davis: > > > Now, the confusing part is the fact that unlike C++, D allows you to put the const for making the function on the _left-hand_ side of the function (C++ only lets you put it on the right). This is to increase consistency between modifers (public, override, pure, etc.) - they _all_ can go on both the right and left (which is very unfortunate in the case of const and immutable IMHO). That means that const (and immutable) always modify the function rather than the return value unless you use parens. > > Some time ago we have discussed this topic in an enhancement request in Bugzilla. The idea was to disallow code like: > > > struct Foo { > int x; > const const(int) bar() { > return 0; > } > } > void main() {} > > > and require the struct "const", "immutable" to be only on the right if present. > Walter shot this idea down for consistency. But I generally don't want > consistency when it's just a potential source of confusion for the > programmer :-) [...] How can this be consistency? For example: class A { const int x; @property const int y(); } Now you have typeof(A.x)==const(int) and typeof(A.y)==int. Seems quite inconsistent to me. But since Walter doesn't like the idea of restricting the syntax to 'int y() const', then what about making it mandatory to write: const(int) x; instead of: const int x; ? Requiring the parentheses is a bit extreme, I admit, but it touches upon another area of D syntax that I don't quite like, and that is const or immutable applied to arrays: const(int)[] x; // array of const(int) const(int[]) x; // const array of int const int[] x; // ??? const array of const int? Or one // of the above? It gets worse when you throw in ref: ref int f(); // returns int* (I think?) ref const(int) f(); // returns const(int)* (?) ref const int f(); // ??? const ref int f(): // ??? The last line is quite bad. Is the return type const(int*) or const(int)*, or is it just int* (i.e., const applies to f not the return value)? ref const(int)[] x; // ref to array of const(int)? const(ref int)[] x; // array of refs to int? const ref int[] x; // array of ??? const ref int[] x(); // const function that returns ref int[]? const const ref int[] x(); // const function returning what? The more I think about this, the more confusing it becomes. If parentheses were mandatory after const, things would be much, much better: const(ref int) x; const(ref const(int)) x; ... etc. Much clearer to me. T -- You have to expect the unexpected. -- RL |
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Tuesday, January 24, 2012 16:24:27 Ali Çehreli wrote:
> On 01/24/2012 04:06 PM, Jonathan M Davis wrote:
> >> class A {
> >> int x;
> >>
> >> const int f1() { ... }
> >> int f2() const { ... }
> >> const(int) f3() { ... }
> >> }
>
> [...]
>
> > int f2() const
> >
> > becomes
> >
> > int f2(const A this)
> >
> > Now, the confusing part is the fact that unlike C++, D allows you to
>
> put the
>
> > const for making the function on the _left-hand_ side of the function
>
> (C++
>
> > only lets you put it on the right).
>
> Ok.
>
> > So, while a C++ programmer expects that
> >
> > int f2() const
> >
> > means that f2 is const, they're likely to be surprised by the fact
>
> that in
>
> > const int f1()
> >
> > it's the int that's const, not f1.
>
> Have you phrased that last bit correctly? :) It seems to conflict with what you have said earlier.
>
> f1() and f2() are the same thing in D.
You're right. I said that incorrectly. f1 and f2 are identical.
- Jonathan M Davis
|
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 01/25/2012 02:29 AM, H. S. Teoh wrote: > On Tue, Jan 24, 2012 at 08:01:41PM -0500, bearophile wrote: >> Jonathan M Davis: >> >>> Now, the confusing part is the fact that unlike C++, D allows you to put the >>> const for making the function on the _left-hand_ side of the function (C++ >>> only lets you put it on the right). This is to increase consistency between >>> modifers (public, override, pure, etc.) - they _all_ can go on both the right >>> and left (which is very unfortunate in the case of const and immutable IMHO). >>> That means that const (and immutable) always modify the function rather than >>> the return value unless you use parens. >> >> Some time ago we have discussed this topic in an enhancement request in Bugzilla. The idea was to disallow code like: >> >> >> struct Foo { >> int x; >> const const(int) bar() { >> return 0; >> } >> } >> void main() {} >> >> >> and require the struct "const", "immutable" to be only on the right if present. >> Walter shot this idea down for consistency. But I generally don't want >> consistency when it's just a potential source of confusion for the >> programmer :-) > [...] > > How can this be consistency? For example: > > class A { > const int x; > @property const int y(); > } > > Now you have typeof(A.x)==const(int) and typeof(A.y)==int. Seems quite > inconsistent to me. > > But since Walter doesn't like the idea of restricting the syntax to 'int > y() const', then what about making it mandatory to write: > > const(int) x; > > instead of: > > const int x; > > ? You essentially propose to remove the const/immutable/shared/inout storage classes for variables. It would break almost every D program and I don't see many benefits. > > Requiring the parentheses is a bit extreme, I admit, but it touches upon > another area of D syntax that I don't quite like, and that is const or > immutable applied to arrays: > > const(int)[] x; // array of const(int) > const(int[]) x; // const array of int > const int[] x; // ??? const array of const int? Or one > // of the above? const(int[]). The storage class of a declaration applies to the whole declaration. > > It gets worse when you throw in ref: Ref does not change anything but the calling convention *of the function*. The reference itself cannot be rebound, there is no syntax for it. > > ref int f(); // returns int* (I think?) > ref const(int) f(); // returns const(int)* (?) > ref const int f(); // ??? > const ref int f(): // ??? > > The last line is quite bad. Is the return type const(int*) or > const(int)*, or is it just int* (i.e., const applies to f not the return > value)? It is int. > > ref const(int)[] x; // ref to array of const(int)? Note that ref can only be on a function or on a parameter. > const(ref int)[] x; // array of refs to int? No such thing exists. > const ref int[] x; // array of ??? const(int[]). Declaration is invalid, would have to be a parameter. > const ref int[] x(); // const function that returns ref int[]? It returns int[], by reference. It is equivalent to int[] x()const ref; Though most people will prefer to have 'ref' on the lhs: ref int[] x()const; It still applies to the function though. > const const ref int[] x(); // const function returning what? Redundant storage class const. ref int[] x()const const; is the same thing. > > The more I think about this, the more confusing it becomes. It is very simple. What may be confusing you is that const/immutable/shared/inout are both type constructors and storage classes. > If > parentheses were mandatory after const, things would be much, much > better: > > const(ref int) x; > const(ref const(int)) x; > ... etc. > > Much clearer to me. It is not to me. This is not valid syntax. Also, types of the general form const(...const(...)...) don't make a lot of sense. Const is transitive. |
January 25, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On Wed, Jan 25, 2012 at 11:50:57PM +0100, Timon Gehr wrote: > On 01/25/2012 02:29 AM, H. S. Teoh wrote: [...] > >But since Walter doesn't like the idea of restricting the syntax to 'int y() const', then what about making it mandatory to write: > > > > const(int) x; > > > >instead of: > > > > const int x; > > > >? > > You essentially propose to remove the const/immutable/shared/inout storage classes for variables. It would break almost every D program and I don't see many benefits. [...] > It is very simple. What may be confusing you is that const/immutable/shared/inout are both type constructors and storage classes. [...] Ah, I see. This is very helpful. So what's the difference between a const int type, and an int variable with const storage class? I think this is the key issue. The syntax makes this distinction non-obvious, IMHO, which is very confusing. This ambiguity also shows up in function definitions (allowing storage classes to appear left or right of the function name/parameters), which we discussed earlier. From what I can tell, Walter doesn't want to change this, but I have to say that this is one part of D I find unnecessarily confusing. T -- Do not reason with the unreasonable; you lose by definition. |
January 26, 2012 Re: Meaning of const | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 01/26/2012 12:35 AM, H. S. Teoh wrote: > On Wed, Jan 25, 2012 at 11:50:57PM +0100, Timon Gehr wrote: >> On 01/25/2012 02:29 AM, H. S. Teoh wrote: > [...] >>> But since Walter doesn't like the idea of restricting the syntax to 'int >>> y() const', then what about making it mandatory to write: >>> >>> const(int) x; >>> >>> instead of: >>> >>> const int x; >>> >>> ? >> >> You essentially propose to remove the const/immutable/shared/inout >> storage classes for variables. It would break almost every D program >> and I don't see many benefits. > [...] >> It is very simple. What may be confusing you is that >> const/immutable/shared/inout are both type constructors and storage >> classes. > [...] > > Ah, I see. This is very helpful. > > So what's the difference between a const int type, and an int variable > with const storage class? > > I think this is the key issue. The syntax makes this distinction > non-obvious, IMHO, which is very confusing. The syntax is clear on it: If it is followed by parentheses, it is a type constructor. Otherwise it is a storage class. > This ambiguity also shows up > in function definitions (allowing storage classes to appear left or > right of the function name/parameters), which we discussed earlier. From > what I can tell, Walter doesn't want to change this, but I have to say > that this is one part of D I find unnecessarily confusing. > For variables, the storage class just implies that the type will be wrapped in the respective type constructor. The storage class still 'talks' about the whole declaration though. A key application is for type deduction: immutable a = foo(); Foo may return something mutable, and a will automatically have it's type deduced to the respective immutable type. Storage classes always apply to the whole declaration they refer to. It is _not_ const int x; and const int foo; but: const int x; and const int foo(){} |
Copyright © 1999-2021 by the D Language Foundation