www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Fixing const arrays

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter and I discussed today and decided to fix this long-standing issue:

import std.algorithm;
void main() {
   const arr = [1, 2, 3];
   reduce!"a*b"(arr);
}

The problem here is that D's built-in arrays are at the same time 
containers and their own ranges. When the array is constant the matter 
becomes confusing because the range itself must be non-constant such 
that it can iterate the constant array.

Put simply, the type of the array in this case should be const(int[]) 
and the type of its range should be const(int)[].

This problem does not commonly occur with ranges because people do 
expect that a constant range can't be used for iteration, and an 
elaborate container will emit the proper type of range even when the 
container itself is constant.

We decided to fix this issue by automatically shedding the top-level 
const when passing an array or a pointer by value into a function.

The rule is simple and does not complicate lookup rules, type deduction, 
or template specialization. It is a semantic rewrite as follows.

Consider x an array of type qualifier(T[]). In any function call in 
which it is established that x is passed by value (i.e. no "ref" with 
the parameter), the call:

fun(..., x, ...)

is lowered into:

fun(..., cast(qualifier(T)[]) x, ...)

after which the usual language rules apply. Similarly, if x has type 
qualifier(T*), AND if x is passed by value into a function, the call:

fun(..., x, ...)

is lowered into:

fun(..., cast(qualifier(T)*) x, ...)

after which, again, the usual rules apply. Note that fun does not need 
to be a template and generally must meet no special conditions aside 
from taking x by value. If fun takes specifically a const(T[]), the call 
will go through no problem because const(T)[] is implicitly convertible 
to const(T[]).

This allows template functions to accept arrays by value yet modify 
their own private copy of the array's bounds, which is reasonable and 
expected.

This rule solves a host of issues related to applying range algorithms 
to arrays. I hope we will have this rule in action in dmd 2.057.


Andrei
Dec 10 2011
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
Andrei Alexandrescu Wrote:
 We decided to fix this issue by automatically shedding the top-level 
 const when passing an array or a pointer by value into a function.

Thank you. Finally.
Dec 10 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, December 10, 2011 15:47:13 Andrei Alexandrescu wrote:
 Walter and I discussed today and decided to fix this long-standing issue:

This looks like a solid decision, and I was actually about to suggest it when thinking about the issues with const ranges today. It's the only sensible solution that I can think of. I was wondering if there might be any negative side effects to it, but I haven't been able to think of any. It would be nice to do the same thing with static arrays, but that would make it harder to pass static arrays to templated functions, and it actually becomes quite dangerous, since it then becomes very easy to mistakenly return references to that static array when the scope is exited. So, I think that the issue of having to slice static arrays should probably remain, but unlike dynamic arrays, static arrays _do_ own their memory, so it's quite reasonably to have to slice them IMHO. The other remaining issue is how to handle tail-const in the general case. Ideally, there would be a way to return a tail-const range from a const range. The only way I can think of enabling that at the moment is to make it so that if opSlice is defined for a type, and it returns the same type (save for how const or immutable it is), then it could be treated the same way as arrays would be as far as template instantiations go (that is, the newly suggested way). But I don't know quite what side-effects that has. Still, I do think that we should find a way to define tail-constness for ranges which are user-defined types. It's not as critical as with arrays, but given the transivity of const, it's still important, since it can be very easy to end up in a situation where it becomes somewhat problematic to get a tail-const range when you're using const much. In any case, I applaud this decision. It should definitely help dealing with arrays as ranges easier. The fact that const and immutable don't work very well at all with ranges at this point is problematic given how const and immutable are supposed to be major features of the language, and this is definitely a step in the right direction. - Jonathan M Davis
Dec 10 2011
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 10/12/2011 22:47, Andrei Alexandrescu a écrit :
 Walter and I discussed today and decided to fix this long-standing issue:

 import std.algorithm;
 void main() {
 const arr = [1, 2, 3];
 reduce!"a*b"(arr);
 }

 The problem here is that D's built-in arrays are at the same time
 containers and their own ranges. When the array is constant the matter
 becomes confusing because the range itself must be non-constant such
 that it can iterate the constant array.

 Put simply, the type of the array in this case should be const(int[])
 and the type of its range should be const(int)[].

 This problem does not commonly occur with ranges because people do
 expect that a constant range can't be used for iteration, and an
 elaborate container will emit the proper type of range even when the
 container itself is constant.

 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

 The rule is simple and does not complicate lookup rules, type deduction,
 or template specialization. It is a semantic rewrite as follows.

 Consider x an array of type qualifier(T[]). In any function call in
 which it is established that x is passed by value (i.e. no "ref" with
 the parameter), the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)[]) x, ...)

 after which the usual language rules apply. Similarly, if x has type
 qualifier(T*), AND if x is passed by value into a function, the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)*) x, ...)

 after which, again, the usual rules apply. Note that fun does not need
 to be a template and generally must meet no special conditions aside
 from taking x by value. If fun takes specifically a const(T[]), the call
 will go through no problem because const(T)[] is implicitly convertible
 to const(T[]).

 This allows template functions to accept arrays by value yet modify
 their own private copy of the array's bounds, which is reasonable and
 expected.

 This rule solves a host of issues related to applying range algorithms
 to arrays. I hope we will have this rule in action in dmd 2.057.


 Andrei

I love to see that. This is going the right way. You deserve your wikipedia page (semi private joke inside).
Dec 10 2011
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
Treating whole constant arrays as ranges by automatically shedding the
top-level const is good.
But realizing it by language semantic change is definitely bad.It
breaks IFTI rule, and adding special case will make difficult to learn
language.

Instead of language change, we can add specializations that receive
non-ranges and convert them to ranges by removing top-level const.
I believe that it is Phobos issue and is never the issue of language.

Kenji

2011/12/11 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 Walter and I discussed today and decided to fix this long-standing issue:

 import std.algorithm;
 void main() {
 =A0const arr =3D [1, 2, 3];
 =A0reduce!"a*b"(arr);
 }

 The problem here is that D's built-in arrays are at the same time contain=

 and their own ranges. When the array is constant the matter becomes
 confusing because the range itself must be non-constant such that it can
 iterate the constant array.

 Put simply, the type of the array in this case should be const(int[]) and
 the type of its range should be const(int)[].

 This problem does not commonly occur with ranges because people do expect
 that a constant range can't be used for iteration, and an elaborate
 container will emit the proper type of range even when the container itse=

 is constant.

 We decided to fix this issue by automatically shedding the top-level cons=

 when passing an array or a pointer by value into a function.

 The rule is simple and does not complicate lookup rules, type deduction, =

 template specialization. It is a semantic rewrite as follows.

 Consider x an array of type qualifier(T[]). In any function call in which=

 is established that x is passed by value (i.e. no "ref" with the paramete=

 the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)[]) x, ...)

 after which the usual language rules apply. Similarly, if x has type
 qualifier(T*), AND if x is passed by value into a function, the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)*) x, ...)

 after which, again, the usual rules apply. Note that fun does not need to=

 a template and generally must meet no special conditions aside from takin=

 by value. If fun takes specifically a const(T[]), the call will go throug=

 no problem because const(T)[] is implicitly convertible to const(T[]).

 This allows template functions to accept arrays by value yet modify their
 own private copy of the array's bounds, which is reasonable and expected.

 This rule solves a host of issues related to applying range algorithms to
 arrays. I hope we will have this rule in action in dmd 2.057.


 Andrei

Dec 10 2011
next sibling parent deadalnix <deadalnix gmail.com> writes:
This is just about removing the constness for whatever the part of a 
type that is passed by value. This is not really a special rule and make 
sense.

Le 10/12/2011 23:31, kenji hara a écrit :
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

 Kenji

 2011/12/11 Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>:
 Walter and I discussed today and decided to fix this long-standing issue:

 import std.algorithm;
 void main() {
   const arr = [1, 2, 3];
   reduce!"a*b"(arr);
 }

 The problem here is that D's built-in arrays are at the same time containers
 and their own ranges. When the array is constant the matter becomes
 confusing because the range itself must be non-constant such that it can
 iterate the constant array.

 Put simply, the type of the array in this case should be const(int[]) and
 the type of its range should be const(int)[].

 This problem does not commonly occur with ranges because people do expect
 that a constant range can't be used for iteration, and an elaborate
 container will emit the proper type of range even when the container itself
 is constant.

 We decided to fix this issue by automatically shedding the top-level const
 when passing an array or a pointer by value into a function.

 The rule is simple and does not complicate lookup rules, type deduction, or
 template specialization. It is a semantic rewrite as follows.

 Consider x an array of type qualifier(T[]). In any function call in which it
 is established that x is passed by value (i.e. no "ref" with the parameter),
 the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)[]) x, ...)

 after which the usual language rules apply. Similarly, if x has type
 qualifier(T*), AND if x is passed by value into a function, the call:

 fun(..., x, ...)

 is lowered into:

 fun(..., cast(qualifier(T)*) x, ...)

 after which, again, the usual rules apply. Note that fun does not need to be
 a template and generally must meet no special conditions aside from taking x
 by value. If fun takes specifically a const(T[]), the call will go through
 no problem because const(T)[] is implicitly convertible to const(T[]).

 This allows template functions to accept arrays by value yet modify their
 own private copy of the array's bounds, which is reasonable and expected.

 This rule solves a host of issues related to applying range algorithms to
 arrays. I hope we will have this rule in action in dmd 2.057.


 Andrei


Dec 10 2011
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

There is no breakage of IFTI, just a reduction of what IFTI sees.
 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

The problem here is scale. We're looking at an absolutely massive code duplication for every single function. I don't think this will ever work; if we do it in Phobos it will make Phobos and by extension the language more difficult to understand AND more bloated for the sake of needless consistency. The language change is legitimate when you think of it this way - it gives template functions back the natural right to change their local state. This right was already there for non-template functions. Andrei
Dec 10 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

I should add there is precedent. C++ also removes top-level const when passing objects by value to templates. Deducing top-level const with pass-by-value is inherently nonsensical. Andrei
Dec 10 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/10/2011 11:41 PM, Andrei Alexandrescu wrote:
 On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

I should add there is precedent. C++ also removes top-level const when passing objects by value to templates. Deducing top-level const with pass-by-value is inherently nonsensical. Andrei

Yes, but in C++ const is not transitive, so this change necessarily introduces some inconsistency. (for the better, I think) struct S{int* x;} void foo(T)(T t){ ... } immutable int x; foo(immutable(S)(&x)); // deduced type needs to be immutable(S)
Dec 10 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/10/11 6:24 PM, kenji hara wrote:
 Posted a test patch to realize the suggestion.
 https://github.com/D-Programming-Language/dmd/pull/554

 Kenji Hara

Many thanks, Kenji, for executing so fast on this! Andrei
Dec 10 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
kenji hara:

 It breaks IFTI rule,

What do you mean?
 and adding special case will make difficult to learn language.

I think that change proposed by Andrei A. (that I like) doesn't add a special case to D2. Currently (2.057beta) this works: void main() { immutable(int[]) a = [1, 2]; immutable(int)[] b = a; } Calling a function that accepts a immutable(int)[] with a immutable(int[]) means creating a local slice, it's similar. So I think Andrei A. removes a special case. Bye, bearophile
Dec 10 2011
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 08:01:57 kenji hara wrote:
 2011/12/11 bearophile <bearophileHUGS lycos.com>:
 kenji hara:
 It breaks IFTI rule,

What do you mean?

I mean following code comment will not become true. void func(T)(T prm){} void main(){ X arg; func(arg); // T is deduced to typeof(arg) }

Why does that matter? What does it affect? As far as functions go, it means that immutable str = "hello"; func(str); would instantiate to func!string instead of func!(immutable string) which will no affect on the internals of the function except for the fact that it's no possible to alter the function parameter. The contents of the array are immutable regardless. In what situation would it matter that it's now func!string instead of func! (immutable string)? - Jonathan M Davis
Dec 10 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 07:31:28 kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.
 
 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

Making the fix in Phobos is a pain in that you have to duplicate functions all over the place (though they'd just be wrappers, so you wouldn't have to duplicate their implementations). And everyone who defines their own range- based functions have to do the same thing. The question is whether we actually lose anything by making it so that so that IFTI won't give you a fully immutable or const array. And I don't see anything that you'd lose or how it could break any code. Sure, it then becomes possible to alter the array within the function where it wasn't before, but if it couldn't before, making it possible now won't break anything, since the function would have to be changed to even try. And for new functions, if they _really_ want the array to be const or immutable, they can assign it to a new array locally. I don't see how any expressiveness is really lost here or that anything would be broken. So, while this _does_ change the language's semantics, it seems to me that it just changes them for the better, not worse. Making this sort of change for static arrays _would_ be a problem, but I don't see how it's an issue for dynamic arrays. - Jonathan M Davis
Dec 10 2011
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
2011/12/11 bearophile <bearophileHUGS lycos.com>:
 kenji hara:

 It breaks IFTI rule,

What do you mean?

I mean following code comment will not become true. void func(T)(T prm){} void main(){ X arg; func(arg); // T is deduced to typeof(arg) }
 and adding special case will make difficult to learn language.

I think that change proposed by Andrei A. (that I like) doesn't add a spe=

 void main() {
 =A0 =A0immutable(int[]) a =3D [1, 2];
 =A0 =A0immutable(int)[] b =3D a;
 }

 Calling a function that accepts a immutable(int)[] with a immutable(int[]=

a special case.
 Bye,
 bearophile

Dec 10 2011
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
2011/12/11 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

I should add there is precedent. C++ also removes top-level const when passing objects by value to templates. Deducing top-level const with pass-by-value is inherently nonsensical. Andrei

Hmm, it's for sure. ---- void print_type(int){} template <typename T> void f(T p) { int n; p = &n; // OK, head is mutable //*p = 10; // NG, tail is const print_type(p); // Error: need explicit cast from int const * to int // T is deduced as int const * == top const is removed } int main() { int n; int const * const p = &n; f(p); return 0; } Kenji
Dec 10 2011
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
OK. I agree to the suggestion.

I've been afraid that increasing IFTI rule is making the language
learning difficult.
It comes from the experience from implementing inout deduction for
template function.

But also it is useful that removing top const when passing arguments by val=
ue.
C++ precedent convinced me.

Thanks.

Kenji Hara

2011/12/11 kenji hara <k.hara.pg gmail.com>:
 2011/12/11 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

I should add there is precedent. C++ also removes top-level const when passing objects by value to templates. Deducing top-level const with pass-by-value is inherently nonsensical. Andrei

Hmm, it's for sure. ---- void print_type(int){} template <typename T> void f(T p) { =A0 =A0int n; =A0 =A0p =3D &n; =A0 =A0 // OK, head is mutable =A0 =A0//*p =3D 10; =A0// NG, tail is const =A0 =A0print_type(p); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Error: need explicit cast from int cons=

 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// T is deduced as int const * =3D=3D top =

 }
 int main()
 {
 =A0 =A0int n;
 =A0 =A0int const * const p =3D &n;
 =A0 =A0f(p);
 =A0 =A0return 0;
 }

 Kenji

Dec 10 2011
prev sibling next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-12-10 21:47:13 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 We decided to fix this issue by automatically shedding the top-level 
 const when passing an array or a pointer by value into a function.

It seems strange that if you implemented the exact same semantic as an a dynamic array or a pointer with a struct it wouldn't work. Basically, you're making a special case by giving two language-defined types characteristics that can't be replicated by user types. I'm not concerned that much, but I thought you worried about those things Andrei. Also seems strange to me that class references aren't included in that list, but then I though about how tail-const still doesn't work with objects. You'd need my const(Object)ref patch to make that work, and Walter hasn't taken time to look at it yet… -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 10 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/10/11 5:20 PM, Michel Fortin wrote:
 On 2011-12-10 21:47:13 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

It seems strange that if you implemented the exact same semantic as an a dynamic array or a pointer with a struct it wouldn't work. Basically, you're making a special case by giving two language-defined types characteristics that can't be replicated by user types. I'm not concerned that much, but I thought you worried about those things Andrei.

I do worry about those things, and this decision comes at the end of a long deliberation. There would be several aspects to discuss here. First, you are right that this confers built-in arrays a property that's not reproducible to user-defined types. And that's a bad thing. Second, that's not really as bad because the real issue is elsewhere. Remember the type "new T[]"? That was supposed to be the array type, which was to be supplanted by its range type, "T[]". After experimentation we decided to give up on that. Why? Because its benefits didn't justify the complication. So the issue we're solving here is that arrays and the ranges that crawl on them are represented by the same type. User-defined types have the option of defining distinct types for that. To truly confer user-defined types the same capability, we should define opPassByValue() which is implicitly invoked whenever an object is passed by value into a function. By default that is a do-nothing operator; for arrays it would do the cast thing (or, equivalently, invoke "[]" on the array), and people could define it to do whatever. We could do all that. The question is, is the added complexity justified?
 Also seems strange to me that class references aren't included in that
 list, but then I though about how tail-const still doesn't work with
 objects. You'd need my const(Object)ref patch to make that work, and
 Walter hasn't taken time to look at it yet…

Have you continued to use your fork in daily work? If so, how does it pan out? Andrei
Dec 10 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 1:30 AM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 01:16:28 Andrei Alexandrescu wrote:
 To truly confer user-defined types the same capability, we should define
 opPassByValue() which is implicitly invoked whenever an object is passed
 by value into a function. By default that is a do-nothing operator; for
 arrays it would do the cast thing (or, equivalently, invoke "[]" on the
 array), and people could define it to do whatever. We could do all that.
 The question is, is the added complexity justified?

I think that it's completely justified. We need a way to define tail-constness for ranges. Given const's transitiveness, it's very easy to end up in a situation where you have a const range, and having a means to get a tail-const version of that range would be very valuable. I don't know if opPassByValue is the best solution, but if not, we at least need a similar one.

I'm not sure. How many times have you been in a place in life where you had a const range on your hands, that's not an array? I haven't. Andrei
Dec 11 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 12/11/2011 12:05 AM, Andrei Alexandrescu wrote:
 I'm not sure. How many times have you been in a place in life where 
 you had a const range on your hands, that's not an array? I haven't.

 Andrei

Hmmm.. isn't that precisely what happens when you define a 'const' method for your (custom) range type? 'this' now becomes a const range.
Dec 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 2:08 AM, Mehrdad wrote:
 On 12/11/2011 12:05 AM, Andrei Alexandrescu wrote:
 I'm not sure. How many times have you been in a place in life where
 you had a const range on your hands, that's not an array? I haven't.

 Andrei

Hmmm.. isn't that precisely what happens when you define a 'const' method for your (custom) range type? 'this' now becomes a const range.

What do you do inside that method? It's reasonable to not expect to change it. Andrei
Dec 11 2011
parent reply Mehrdad <wfunction hotmail.com> writes:
On 12/11/2011 12:14 AM, Andrei Alexandrescu wrote:
 What do you do inside that method? It's reasonable to not expect to 
 change it.

 Andrei

Not sure right now, but something along the lines of auto copy = this; foreach (v; copy) ....; sounds like code I've definitely seen before.
Dec 11 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 2:36 AM, Mehrdad wrote:
 On 12/11/2011 12:14 AM, Andrei Alexandrescu wrote:
 What do you do inside that method? It's reasonable to not expect to
 change it.

 Andrei

Not sure right now, but something along the lines of auto copy = this; foreach (v; copy) ....; sounds like code I've definitely seen before.

I think you should write: auto copy = this.save; Andrei
Dec 11 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 12/11/2011 12:57 AM, Andrei Alexandrescu wrote:
 I think you should write:

 auto copy = this.save;


 Andrei

Ah good point, I forgot about that. Idk then. (You forgot the parentheses though. :P)
Dec 11 2011
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2011 1:04 AM, Mehrdad wrote:
 On 12/11/2011 12:57 AM, Andrei Alexandrescu wrote:
 I think you should write:

 auto copy = this.save;


 Andrei

Ah good point, I forgot about that. Idk then. (You forgot the parentheses though. :P)

Try the new beta http://ftp.digitalmars.com/dmd2beta.zip
Dec 11 2011
parent Mehrdad <wfunction hotmail.com> writes:
On 12/11/2011 1:54 AM, Walter Bright wrote:
 Try the new beta
 http://ftp.digitalmars.com/dmd2beta.zip

to fix it! I'll post if I come across similar/related problems. :)
Dec 11 2011
prev sibling next sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 12/11/11 10:04 AM, Mehrdad wrote:
 On 12/11/2011 12:57 AM, Andrei Alexandrescu wrote:
 I think you should write:

 auto copy = this.save;

Ah good point, I forgot about that. Idk then. (You forgot the parentheses though. :P)

No, it's correct like that, save() is a property. Even though I recently updated Phobos to compile with -property enabled, I agree with Andrei here that in many cases there will be no perfect consensus whether a given member should be a property or not, thus potentially adding an extra source of complexity, or rather annoyance. David
Dec 11 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 12/11/2011 2:56 AM, David Nadlinger wrote:
 On 12/11/11 10:04 AM, Mehrdad wrote:
 On 12/11/2011 12:57 AM, Andrei Alexandrescu wrote:
 I think you should write:

 auto copy = this.save;

Ah good point, I forgot about that. Idk then. (You forgot the parentheses though. :P)

No, it's correct like that, save() is a property. Even though I recently updated Phobos to compile with -property enabled, I agree with Andrei here that in many cases there will be no perfect consensus whether a given member should be a property or not, thus potentially adding an extra source of complexity, or rather annoyance. David

Whoa what?! I didn't know save() is a property. In that case I stand corrected. :-) Nevertheless, I think that makes no sense. :P If something isn't a "property" of something else, it shouldn't be marked as such. But there are more reasons than that... I have found Microsoft's guidelines for C# to be great for general usage of the word property: http://msdn.microsoft.com/en-us/library/ms182181.aspx Specifically: "Properties should behave as if they are fields; if the method cannot, it should not be changed to a property. Methods are better than properties in the following situations: - Calling the method two times in succession creates different results. - The method performs a time-consuming operation. The method is perceivably slower than the time that is required to set or get the value of a field." Since both of these can be true for all but the most trivial kinds of ranges (e.g. file-system-related enumerators/ranges would very likely need to re-open a handle to a directory in order to traverse it, which is both relatively time-consuming AND returns a different result every time, and could even unexpectedly fail due to permission/connectivity issues), I don't think it makes sense for save() to be a property.
Dec 11 2011
next sibling parent reply Tobias Pankrath <tobias pankrath.net> writes:
 Specifically:
 
 "Properties should behave as if they are fields; if the method cannot,
 it should not be changed to a property.
 Methods are better than properties in the following situations:
 
 - Calling the method two times in succession creates different results.
 - The method performs a time-consuming operation. The method is
 perceivably slower than the time that is required to set or get the
 value of a field."
 
 Since both of these can be true for all but the most trivial kinds of
 ranges (e.g. file-system-related enumerators/ranges would very likely
 need to re-open a handle to a directory in order to traverse it, which
 is both relatively time-consuming AND returns a different result every
 time, and could even unexpectedly fail due to permission/connectivity
 issues), I don't think it makes sense for save() to be a  property.

I agree.
Dec 11 2011
next sibling parent Max Samukha <maxsamukha gmail.com> writes:
On 12/11/2011 11:24 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 14:54:27 Tobias Pankrath wrote:
 Specifically:

 "Properties should behave as if they are fields; if the method cannot,
 it should not be changed to a property.
 Methods are better than properties in the following situations:

 - Calling the method two times in succession creates different results.
 - The method performs a time-consuming operation. The method is
 perceivably slower than the time that is required to set or get the
 value of a field."

 Since both of these can be true for all but the most trivial kinds of
 ranges (e.g. file-system-related enumerators/ranges would very likely
 need to re-open a handle to a directory in order to traverse it, which
 is both relatively time-consuming AND returns a different result every
 time, and could even unexpectedly fail due to permission/connectivity
 issues), I don't think it makes sense for save() to be a  property.

I agree.

It was debated some time ago, and it ended up being a property. The fact that save is an action verb and not a noun automatically disqualifies it as a property IMHO, but it was made into a property, and we're pretty much stuck with it at some point. As far as what the function does, I don't think that it's a problem that it's a property, but it's not named like a property, so the situation with regards to save is not ideal, but it's too late now. - Jonathan M Davis

Reminds me of .NET's Object.GetHashCode() method, which should be a property according to their guide. Another is Object.GetType() - why is it not a property anyway? Both are supposed to return the same value on succesive calls and both are computationally cheap. Other examples are widget size setters that can be computationally quite expensive (resizing child widgets, etc.). They are usually property setters regardless of the fact that they are "perceivably slower" to set than fields.
Dec 12 2011
prev sibling parent reply torhu <no spam.invalid> writes:
On 11.12.2011 22:24, Jonathan M Davis wrote:
...
 It was debated some time ago, and it ended up being a property. The fact that
 save is an action verb and not a noun automatically disqualifies it as a
 property IMHO, but it was made into a property, and we're pretty much stuck
 with it at some point. As far as what the function does, I don't think that
 it's a problem that it's a property, but it's not named like a property, so
 the situation with regards to save is not ideal, but it's too late now.

I really don't get this. When D has 10,000 programmers using it professionally, it's too late. But now it's more like 5 or 10. And they are all presumably aware that D2 is still undergoing some polish. So are the maybe a few hundred people that are using D for hobby projects. They are early adopters, and they know what that entails. I call bogus on the backwards compatibility argument. There's not a lot to be compatible with at this stage. Not compared to what D2 wants to become. As for Andrei's book using save with the parentheses: If D2 gains traction, I'm sure there will be a second edition of that book. And you already want to have the errata handy when using the book. I don't see what the big deal is, at least not compared to letting this stay in the language forever. save being a property is a stupid inconsistency. It's easy to fix, the cost is relatively low. The people using D2 now are all part of a community that want D to succeed, as am I. It's a change for the better, which I'm sure most current D2 users would agree with. How hard can it be?
Dec 12 2011
next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-12-12 12:38:09 +0000, "Jakob Ovrum" <jakobovrum gmail.com> said:

 Furthermore, there weren't even a way to enforce the property syntax 
 until lately, and it's still not enabled by default. If we change it 
 right now, people still have time to adapt before the 
 backwards-compatibility argument even kicks in (no matter how weak it 
 is).

Indeed. As far as we know, there might be more people out there using save as a function than there are using save as a property. We don't know that because it isn't enforced and people will simply use what they feel is best. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 12 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 6:24 AM, torhu wrote:
 save being a property is a stupid inconsistency.

I'm not so sure. Andrei
Dec 12 2011
parent reply torhu <no spam.invalid> writes:
On 12.12.2011 15:43, Andrei Alexandrescu wrote:
 On 12/12/11 6:24 AM, torhu wrote:
  save being a property is a stupid inconsistency.

I'm not so sure. Andrei

Why? As far as I can tell, it's inconsistent with what properties are used like in other programming languages. Saving something is an action, which to me is a different concept. If it was called currentState instead, that's what I'd call a property. Making something a property gives it certain connotations that break when it's called 'save'. That you can save the state of the range is a property, if you will. But the action of doing so is not a property. People are going to be surprised when save() doesn't compile. Isn't there something called the principle of least surprise?
Dec 12 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 9:09 AM, torhu wrote:
 On 12.12.2011 15:43, Andrei Alexandrescu wrote:
 On 12/12/11 6:24 AM, torhu wrote:
 save being a property is a stupid inconsistency.

I'm not so sure. Andrei

Why? As far as I can tell, it's inconsistent with what properties are used like in other programming languages.

Why?
 Saving something is an action,
 which to me is a different concept.

So if we called .save .state or .current things would be any different?
 If it was called currentState
 instead, that's what I'd call a property.

Ah. So now we're wasting time not on property (as I'd predicted), but instead on what _names_ are suitable to work with it. I rest my case.
 Making something a property gives it certain connotations that break
 when it's called 'save'. That you can save the state of the range is a
 property, if you will. But the action of doing so is not a property.
 People are going to be surprised when save() doesn't compile. Isn't
 there something called the principle of least surprise?

I think we should only worry about surprising the uninitiated with how poorly designed the whole property thing is. Andrei
Dec 12 2011
next sibling parent torhu <no spam.invalid> writes:
On 12.12.2011 16:16, Andrei Alexandrescu wrote:
 On 12/12/11 9:09 AM, torhu wrote:
  On 12.12.2011 15:43, Andrei Alexandrescu wrote:
  On 12/12/11 6:24 AM, torhu wrote:
  save being a property is a stupid inconsistency.

I'm not so sure. Andrei

Why? As far as I can tell, it's inconsistent with what properties are used like in other programming languages.

Why?
  Saving something is an action,
  which to me is a different concept.

So if we called .save .state or .current things would be any different?

Yes, completely. The whole property concept is basically a naming convention. Except that parentheses are now involved. x = obj.foo(); // do the foo thing, then return something x = obj.bar; // get bar obj.bar = 42; // set bar x = obj.save; // get save... hm, that doesn't sound right
  If it was called currentState
  instead, that's what I'd call a property.

Ah. So now we're wasting time not on property (as I'd predicted), but instead on what _names_ are suitable to work with it. I rest my case.
  Making something a property gives it certain connotations that break
  when it's called 'save'. That you can save the state of the range is a
  property, if you will. But the action of doing so is not a property.
  People are going to be surprised when save() doesn't compile. Isn't
  there something called the principle of least surprise?

I think we should only worry about surprising the uninitiated with how poorly designed the whole property thing is.

I'm not trying to defend property, I think it adds about as much pain as it does gain. But it's there, and your ranges are using it :)
Dec 12 2011
prev sibling next sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 12/12/11 3:16 PM, Andrei Alexandrescu wrote:
 On 12/12/11 9:09 AM, torhu wrote:
 On 12.12.2011 15:43, Andrei Alexandrescu wrote:
 On 12/12/11 6:24 AM, torhu wrote:
 save being a property is a stupid inconsistency.

I'm not so sure. Andrei

Why? As far as I can tell, it's inconsistent with what properties are used like in other programming languages.

Why?

My understanding is the properties are essentially meant to be indistinguishable from fields (hence the syntax). save() doesn't really act like a field. Honestly though, I don't like properties at all (in any language). Function calls should not be hidden in syntax. IMO if your code contains so many get/set functions that properties save you time then you have bigger issues.
Dec 12 2011
prev sibling parent reply torhu <no spam.invalid> writes:
On 12.12.2011 20:03, Jonathan M Davis wrote:
 On Monday, December 12, 2011 09:16:53 Andrei Alexandrescu wrote:
  On 12/12/11 9:09 AM, torhu wrote:
  >  On 12.12.2011 15:43, Andrei Alexandrescu wrote:
  >>  On 12/12/11 6:24 AM, torhu wrote:
  >>>  save being a property is a stupid inconsistency.
  >>
  >>  I'm not so sure.
  >>
  >>  Andrei
  >
  >  Why? As far as I can tell, it's inconsistent with what properties are
  >  used like in other programming languages.

  Why?

  >  Saving something is an action,
  >  which to me is a different concept.

  So if we called .save .state or .current things would be any different?

  >  If it was called currentState
  >  instead, that's what I'd call a property.

  Ah. So now we're wasting time not on  property (as I'd predicted), but
  instead on what _names_ are suitable to work with it. I rest my case.

  >  Making something a property gives it certain connotations that break
  >  when it's called 'save'. That you can save the state of the range is a
  >  property, if you will. But the action of doing so is not a property.
  >  People are going to be surprised when save() doesn't compile. Isn't
  >  there something called the principle of least surprise?

  I think we should only worry about surprising the uninitiated with how
  poorly designed the whole  property thing is.

A property is essentially an abstraction to treat a function like a member variable. As such, the naming conventions for a property should be equivalent to those for a variable - and that generally means nouns. save is not a noun. It's an action verb. So, yes, I think that it's a completely inappropriate name for a property. Something ilke state or current _would_ be appropriate names. However, at this point, I really don't think that it's worth arguing about. If I were to change it, I'd probably just make save a function rather than renaming it, but if we did it, then there would be quite a bit of code that would have to be changed essentially over an argument over whether save is valid property name because it's not a noun. And while I _don't_ think that it's a valid property name, that's getting a bit petty given how much code would break.

It's actually not 'save' being a noun that's the problem. I just thought of a counter-example: --- struct Foo { // the data Bar data[]; // save data on shutdown? property bool save() { return save_; } property bool save(bool shouldShave) { return save_ = shouldSave; } private: bool save_; } --- Not meant to be a realistic example, but save is fine as a property here.
Dec 12 2011
parent torhu <no spam.invalid> writes:
On 13.12.2011 02:39, Jonathan M Davis wrote:
 On Tuesday, December 13, 2011 02:28:29 torhu wrote:
 It's actually not 'save' being a noun that's the problem. I just
 thought of a counter-example:

 --- struct Foo { // the data Bar data[];

 // save data on shutdown?  property bool save() { return save_; }
  property bool save(bool shouldShave) { return save_ = shouldSave;
 }

 private: bool save_; } --- Not meant to be a realistic example, but
 save is fine as a property here.

You can pretty much always come up with another function with a completely different purpose wit the same name. Personally, the _only_ issue that I have with save is the fact that it's a property. The name save works well enough, and I can't think of anything that's better.

Yes, that's my opinion too.
Dec 12 2011
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, December 12, 2011 09:16:53 Andrei Alexandrescu wrote:
 On 12/12/11 9:09 AM, torhu wrote:
 On 12.12.2011 15:43, Andrei Alexandrescu wrote:
 On 12/12/11 6:24 AM, torhu wrote:
 save being a property is a stupid inconsistency.

I'm not so sure. Andrei

Why? As far as I can tell, it's inconsistent with what properties are used like in other programming languages.

Why?
 Saving something is an action,
 which to me is a different concept.

So if we called .save .state or .current things would be any different?
 If it was called currentState
 instead, that's what I'd call a property.

Ah. So now we're wasting time not on property (as I'd predicted), but instead on what _names_ are suitable to work with it. I rest my case.
 Making something a property gives it certain connotations that break
 when it's called 'save'. That you can save the state of the range is a
 property, if you will. But the action of doing so is not a property.
 People are going to be surprised when save() doesn't compile. Isn't
 there something called the principle of least surprise?

I think we should only worry about surprising the uninitiated with how poorly designed the whole property thing is.

A property is essentially an abstraction to treat a function like a member variable. As such, the naming conventions for a property should be equivalent to those for a variable - and that generally means nouns. save is not a noun. It's an action verb. So, yes, I think that it's a completely inappropriate name for a property. Something ilke state or current _would_ be appropriate names. However, at this point, I really don't think that it's worth arguing about. If I were to change it, I'd probably just make save a function rather than renaming it, but if we did it, then there would be quite a bit of code that would have to be changed essentially over an argument over whether save is valid property name because it's not a noun. And while I _don't_ think that it's a valid property name, that's getting a bit petty given how much code would break. I'm all for fixing names for camelcasing, because that really affects the consistency of the library and is almost always completely objective, but this is essentially an argument over the best name for a function, and that never has a clear answer. Yes, it's an issue of consistency on some level with regards to how we treat and name properties, but that's subjective enough that I don't expect us to ever be completely consistent on that. - Jonathan M Davis
Dec 12 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 6:49 AM, Manu wrote:
 I think every opportunity should be taken to make important breaking
 changes while the community is as small as it is.

Changing from r.save to r.save() is NOT an important change. It makes no semantic difference, marks no progress, and has no consequence. Insisting on the current property semantics was a sizeable mistake of this community, and I am sorry we gave into it. Andrei
Dec 12 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he shouldn't need
 to know, it should be fast and cheap, and return a consistent value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei
Dec 12 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/12/2011 04:29 PM, Jakob Ovrum wrote:
 On Monday, 12 December 2011 at 15:14:02 UTC, Andrei Alexandrescu wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he shouldn't need
 to know, it should be fast and cheap, and return a consistent value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei

But save is an abstract interface function, its signature should reflect all possible implementations.

Under the premise that a function should be a property iff it behaves like a field, that is impossible.
Dec 12 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 9:29 AM, Jakob Ovrum wrote:
 On Monday, 12 December 2011 at 15:14:02 UTC, Andrei Alexandrescu wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he shouldn't need
 to know, it should be fast and cheap, and return a consistent value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei

But save is an abstract interface function, its signature should reflect all possible implementations.

Same goes for many properties. Andrei
Dec 12 2011
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, December 12, 2011 17:24:38 Jakob Ovrum wrote:
 I'm still a beginner with ranges, but by my understanding and by
 what some people made it sound like, reasonable uses of save
 include some which are non-trivial. If this is true, then
 removing  property from save encourages people to think more
 about what using it might mean for the code they are writing,
 which is definitely important.

Both save and postblit are supposed to be trivial. Algorithms generally assume that copying a range is O(1). There's nothing stopping save and postblit from costing more than that, but it's going to harm performance. - Jonathan M Davis
Dec 12 2011
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 The old situation where you could
 write complete nonsense code like `std.file.read = "foo.txt";` is far
 worse.

We could have defined a system much better than both. Andrei
Dec 12 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None. Andrei
Dec 12 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/13/2011 01:08 AM, Steven Schveighoffer wrote:
 On Mon, 12 Dec 2011 19:00:35 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:

 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

Wait, are we talking about property or .save? -Steve

definitely property.
Dec 13 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/13/11 10:32 AM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 18:00:35 Andrei Alexandrescu wrote:
 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

So, you prefer the situation where any function with no arguments can be used as a getter and any function with a single argument can be used as a setter?

No. That would be a false choice. Andrei
Dec 13 2011
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 13, 2011 12:25:12 Jonathan M Davis wrote:
 On Tuesday, December 13, 2011 14:02:51 Andrei Alexandrescu wrote:
 On 12/13/11 10:32 AM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 18:00:35 Andrei Alexandrescu wrote:
 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable
 mistake
 of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

So, you prefer the situation where any function with no arguments can be used as a getter and any function with a single argument can be used as a setter?

No. That would be a false choice.

I'm not saying that those are the only choices, but you seem to think that the current situation is worse than what we had before, which I don't understand. The current situation looks all around better to me.

In fact, what _would_ you prefer to property if it's not what we had before? - Jonathan M Davis
Dec 13 2011
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/13/11 2:25 PM, Jonathan M Davis wrote:
 On Tuesday, December 13, 2011 14:02:51 Andrei Alexandrescu wrote:
 On 12/13/11 10:32 AM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 18:00:35 Andrei Alexandrescu wrote:
 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake
 of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

So, you prefer the situation where any function with no arguments can be used as a getter and any function with a single argument can be used as a setter?


I'm not saying that those are the only choices, but you seem to think that the current situation is worse than what we had before, which I don't understand. The current situation looks all around better to me.

There's a phrase in Romanian that quite applies: "From the lake into the well". Andrei
Dec 13 2011
next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length) 2. Complicating the language (proof: this discussion) 3. Another thing to learn. 4. Another thing for tools to process. I don't think the syntax sugar it provides counts for anything really. The ability to refactor member look ups is nice, but I find that this rarely occurs in practice and even when it occurs, it's not hard to replace obj.field with obj.field() or obj.getField(). The costs far outweigh the benefits IMO.
Dec 13 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/13/11 5:14 PM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length) 2. Complicating the language (proof: this discussion) 3. Another thing to learn. 4. Another thing for tools to process. I don't think the syntax sugar it provides counts for anything really. The ability to refactor member look ups is nice, but I find that this rarely occurs in practice and even when it occurs, it's not hard to replace obj.field with obj.field() or obj.getField(). The costs far outweigh the benefits IMO.

We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of property we have now. I noticed there's a tunnel vision phenomenon when it comes to keyword-based solutions: once a special notation is on the table, there's no appreciation for anything else. That's what happened with lazy (another design misfire I'm very unhappy about) and with property. I literally feel my heart rate getting up when I think of them. Andrei
Dec 13 2011
next sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 We could have inferred property intention from the code pattern, 
 without requiring any keyword. That solution (which was discussed and 
 rejected in this newsgroup) was miles ahead from the drivel of 
  property we have now.

By "code patterns", you mean something like this? struct Foo { int getBar(); void setBar(int); } void main() { Foo foo; int a = foo.bar; // calls getBar() foo.bar = a; // calls setBar(a) } I agree it's better. For one thing it'd be much less confusing about whether it make sense to make something a property or not because you'd have to write "get" in front of it -- for instance getSave doesn't make any sense. And it'd be much less problematic too: the way property is currently designed, you can't distinguish between a definition for a an array-member property getter and a module-level property setter. Also with the current design you have no way to disambiguate array-member properties with the same name coming from different modules -- can't replace array.front with std.range.front(array) when property is enforced -- having access to the property's underlying function would mitigate this -- std.range.getFront(array) would still work. The above code pattern would also make it saner to take the address of the getter function as a separate thing from taking the address of a ref value obtained from a property. Personally, I'm skeptical the current property design can work as intended without introducing many issues like the above. I think perhaps the biggest mistake was to not implement it fully from the start at a time where we could easily revert to another proposition if it proved to be problematic. Unfortunately, now we're stuck with property and all its problems… although I'd sure like the design to be revised. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 13 2011
parent Michel Fortin <michel.fortin michelf.com> writes:
On 2011-12-14 13:27:57 +0000, "Regan Heath" <regan netmail.co.nz> said:

 On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin
 <michel.fortin michelf.com> wrote:
 
 By "code patterns", you mean something like this?
 
 	struct Foo
 	{
 		int getBar();
 		void setBar(int);
 	}
 
 	void main()
 	{
 		Foo foo;
 		int a = foo.bar;  // calls getBar()
 		foo.bar = a;      // calls setBar(a)
 	}

Why not something similar to C# syntax...

I know the basics of the C# property syntax, but how do you take the address of the getter with it? And how do you define array-member properties like you can do with functions? And how do you disambiguate access those array members properties if two imported modules define a property with the same name for an array? It basically has the same undefined areas as the current syntax using property. With the code pattern syntax used above: &foo.bar; // take the address of the returned value (if returned by ref) &foo.getBar; // take the address of the getter &foo.setBar; // take the address of the setter void getFront(int[] array) { return array[0]; } int[] a; a.front; // array-member property made from a module-level function // disambiguated access if two imported modules // define the same array-member property std.range.getFront(a); other.mod.getFront(a); -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 14 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 13, 2011 21:36:43 Michel Fortin wrote:
 On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu
=20
 <SeeWebsiteForEmail erdani.org> said:
 We could have inferred property intention from the code pattern,
 without requiring any keyword. That solution (which was discussed a=


 rejected in this newsgroup) was miles ahead from the drivel of
  property we have now.

By "code patterns", you mean something like this? =20 =09struct Foo =09{ =09=09int getBar(); =09=09void setBar(int); =09} =20 =09void main() =09{ =09=09Foo foo; =09=09int a =3D foo.bar; // calls getBar() =09=09foo.bar =3D a; // calls setBar(a) =09} =20 I agree it's better. For one thing it'd be much less confusing about whether it make sense to make something a property or not because you=

 have to write "get" in front of it -- for instance getSave doesn't ma=

 any sense.
=20
 And it'd be much less problematic too: the way  property is currently=

 designed, you can't distinguish between a definition for a an
 array-member property getter and a module-level property setter. Also=

 with the current design you have no way to disambiguate array-member
 properties with the same name coming from different modules -- can't
 replace array.front with std.range.front(array) when  property is
 enforced -- having access to the  property's underlying function woul=

 mitigate this -- std.range.getFront(array) would still work. The abov=

 code pattern would also make it saner to take the address of the gett=

 function as a separate thing from taking the address of a ref value
 obtained from a property.
=20
 Personally, I'm skeptical the current property design can work as
 intended without introducing many issues like the above. I think
 perhaps the biggest mistake was to not implement it fully from the
 start at a time where we could easily revert to another proposition i=

 it proved to be problematic. Unfortunately, now we're stuck with
  property and all its problems=E2=80=A6 although I'd sure like the de=

 revised.

I'd think that some revision would be possible even if it breaks code a= s long=20 as there is great need for it - though that would depend on Walter's de= cision.=20 But since property is in TDPL, a complete redesign wouldn't make sense= =20 without _major_ need. Smaller tweaks wouldn't be as big a deal though. = I'm not=20 quite sure how property would be adjusted for some of these corner cas= es=20 though. The basic idea works well for member functions, but once you ad= d free=20 functions into the mix, it gets more complicated. - Jonathan M Davis
Dec 13 2011
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.
 2. Complicating the language (proof: this discussion)
 3. Another thing to learn.
 4. Another thing for tools to process.


 I don't think the syntax sugar it provides counts for anything really.

 The ability to refactor member look ups is nice, but I find that this
 rarely occurs in practice and even when it occurs, it's not hard to
 replace obj.field with obj.field() or obj.getField().

 The costs far outweigh the benefits IMO.

Dec 13 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy
Dec 13 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/14/2011 12:35 AM, Peter Alexander wrote:
 On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.
Dec 14 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 14/12/11 8:16 AM, Timon Gehr wrote:
 On 12/14/2011 12:35 AM, Peter Alexander wrote:
 On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.

Well, it is a little. It makes it difficult to scan code looking for GC allocations, or even scan code looking for inefficiencies. Obviously I know now that I have to look for .length assignments on arrays, but it can be quite horrific when looking at code that uses third party libraries that you aren't familiar with. An example of this I encountered in practice was in Unity3D's libraries. http://unity3d.com/support/documentation/ScriptReference/WWW-texture.html The WWW class has a 'texture' property. A small sentence in the middle of its documentation reveals the horror. "Each invocation of texture property allocates a new Texture2D." That's right. Every time you read WWW.texture, it allocates a large chunk of memory. In my particular case, I was copying the pixels from the texture into another array, something like this: WWW www = ...; for (int i = 0; i < www.texture.width; ++i) for (int j = 0; j < www.texture.height; ++j) buffer[i][j] = www.texture.GetPixel(i, j); For a small 100x100 texture, that code allocates over 10,000, 100x100 textures. Luckily, that was horrific enough to prompt me to investigate, but a less obvious problem would have likely slipped past me unnoticed.
Dec 14 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/14/2011 09:39 PM, Peter Alexander wrote:
 On 14/12/11 8:16 AM, Timon Gehr wrote:
 On 12/14/2011 12:35 AM, Peter Alexander wrote:
 On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.

Well, it is a little. It makes it difficult to scan code looking for GC allocations, or even scan code looking for inefficiencies. Obviously I know now that I have to look for .length assignments on arrays, but it can be quite horrific when looking at code that uses third party libraries that you aren't familiar with.

Oh yes, certainly. That is what I meant by 'in this particular case': Because the .length on arrays is built into the language, you know that it must allocate as soon as you have a sufficiently good mental model of how dynamic arrays work. (and anyone who wants to write effective D code that uses dynamic arrays should)
 An example of this I encountered in practice was in Unity3D's libraries.

 http://unity3d.com/support/documentation/ScriptReference/WWW-texture.html

 The WWW class has a 'texture' property. A small sentence in the middle
 of its documentation reveals the horror.

 "Each invocation of texture property allocates a new Texture2D."

 That's right. Every time you read WWW.texture, it allocates a large
 chunk of memory. In my particular case, I was copying the pixels from
 the texture into another array, something like this:

 WWW www = ...;

 for (int i = 0; i < www.texture.width; ++i)
 for (int j = 0; j < www.texture.height; ++j)
 buffer[i][j] = www.texture.GetPixel(i, j);

 For a small 100x100 texture, that code allocates over 10,000, 100x100
 textures.

 Luckily, that was horrific enough to prompt me to investigate, but a
 less obvious problem would have likely slipped past me unnoticed.

oO. That is quite an API design problem there.
Dec 14 2011
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Peter Alexander:

 Well, it is a little. It makes it difficult to scan code looking for GC 
 allocations, or even scan code looking for inefficiencies.
 
 Obviously I know now that I have to look for .length assignments on 
 arrays, but it can be quite horrific when looking at code that uses 
 third party libraries that you aren't familiar with.

A proposed idea to help is to add a compilation switch that produces a list of all heap allocation points in the current compilation unit (in Bugzilla there is a related issue that asks for a list of just heap allocations of closures). Bye, bearophile
Dec 14 2011
prev sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 14/12/11 8:59 PM, Steven Schveighoffer wrote:
 On Wed, 14 Dec 2011 15:39:55 -0500, Peter Alexander
 <peter.alexander.au gmail.com> wrote:

 On 14/12/11 8:16 AM, Timon Gehr wrote:
 On 12/14/2011 12:35 AM, Peter Alexander wrote:
 On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake
 into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.

Well, it is a little. It makes it difficult to scan code looking for GC allocations, or even scan code looking for inefficiencies. Obviously I know now that I have to look for .length assignments on arrays, but it can be quite horrific when looking at code that uses third party libraries that you aren't familiar with. An example of this I encountered in practice was in Unity3D's libraries. http://unity3d.com/support/documentation/ScriptReference/WWW-texture.html The WWW class has a 'texture' property. A small sentence in the middle of its documentation reveals the horror. "Each invocation of texture property allocates a new Texture2D." That's right. Every time you read WWW.texture, it allocates a large chunk of memory. In my particular case, I was copying the pixels from the texture into another array, something like this: WWW www = ...; for (int i = 0; i < www.texture.width; ++i) for (int j = 0; j < www.texture.height; ++j) buffer[i][j] = www.texture.GetPixel(i, j); For a small 100x100 texture, that code allocates over 10,000, 100x100 textures. Luckily, that was horrific enough to prompt me to investigate, but a less obvious problem would have likely slipped past me unnoticed.

Yes, but length as a read property does not allocate anything (nor does reducing the length). In fact, length as a read property reduces to a field access (it is a language builtin, after all).

Length reading is fine.
 Would you expect that setting the length of an array to a *larger* size
 would not allocate? Your example shows something that doesn't look like
 it should be costly, but it actually is. Expanding length *looks* costly
 (and it is).

It's not that I wouldn't expect it (I would), but at a glance (i.e. without thinking about it) you wouldn't notice it. It just looks like a member assignment. It's like overloading operator& in C++. It takes something that had one meaning and changes it into something else without a change in syntax. It's essentially the syntactic version of function hijacking.
 You do have a point that it shouldn't necessarily be a property. I also
 don't think dup, reverse, or sort should be array properties. But these
 are pieces of the language that have been there forever. To change them
 now would be disruptive for very little gain.

Agreed.
Dec 14 2011
prev sibling parent simendsjo <simendsjo gmail.com> writes:
On 13.12.2011 23:17, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :)

The Norwegian version is "From ashes to fire" (direct translation) or "From the ashes into the fire"
Dec 14 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 14:54:27 Tobias Pankrath wrote:
 Specifically:
 
 "Properties should behave as if they are fields; if the method cannot,
 it should not be changed to a property.
 Methods are better than properties in the following situations:
 
 - Calling the method two times in succession creates different results.
 - The method performs a time-consuming operation. The method is
 perceivably slower than the time that is required to set or get the
 value of a field."
 
 Since both of these can be true for all but the most trivial kinds of
 ranges (e.g. file-system-related enumerators/ranges would very likely
 need to re-open a handle to a directory in order to traverse it, which
 is both relatively time-consuming AND returns a different result every
 time, and could even unexpectedly fail due to permission/connectivity
 issues), I don't think it makes sense for save() to be a  property.

I agree.

It was debated some time ago, and it ended up being a property. The fact that save is an action verb and not a noun automatically disqualifies it as a property IMHO, but it was made into a property, and we're pretty much stuck with it at some point. As far as what the function does, I don't think that it's a problem that it's a property, but it's not named like a property, so the situation with regards to save is not ideal, but it's too late now. - Jonathan M Davis
Dec 11 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 12:24:53 UTC, torhu wrote:
 On 11.12.2011 22:24, Jonathan M Davis wrote:
 ...
 It was debated some time ago, and it ended up being a 
 property. The fact that
 save is an action verb and not a noun automatically 
 disqualifies it as a
 property IMHO, but it was made into a property, and we're 
 pretty much stuck
 with it at some point. As far as what the function does, I 
 don't think that
 it's a problem that it's a property, but it's not named like a 
 property, so
 the situation with regards to save is not ideal, but it's too 
 late now.

I really don't get this. When D has 10,000 programmers using it professionally, it's too late. But now it's more like 5 or 10. And they are all presumably aware that D2 is still undergoing some polish. So are the maybe a few hundred people that are using D for hobby projects. They are early adopters, and they know what that entails. I call bogus on the backwards compatibility argument. There's not a lot to be compatible with at this stage. Not compared to what D2 wants to become. As for Andrei's book using save with the parentheses: If D2 gains traction, I'm sure there will be a second edition of that book. And you already want to have the errata handy when using the book. I don't see what the big deal is, at least not compared to letting this stay in the language forever. save being a property is a stupid inconsistency. It's easy to fix, the cost is relatively low. The people using D2 now are all part of a community that want D to succeed, as am I. It's a change for the better, which I'm sure most current D2 users would agree with. How hard can it be?

Furthermore, there weren't even a way to enforce the property syntax until lately, and it's still not enabled by default. If we change it right now, people still have time to adapt before the backwards-compatibility argument even kicks in (no matter how weak it is).
Dec 12 2011
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--20cf303b4147979a2604b3e48f62
Content-Type: text/plain; charset=UTF-8

On 12 December 2011 14:24, torhu <no spam.invalid> wrote:

 On 11.12.2011 22:24, Jonathan M Davis wrote:
 ...

  It was debated some time ago, and it ended up being a property. The fact
 that
 save is an action verb and not a noun automatically disqualifies it as a
 property IMHO, but it was made into a property, and we're pretty much
 stuck
 with it at some point. As far as what the function does, I don't think
 that
 it's a problem that it's a property, but it's not named like a property,
 so
 the situation with regards to save is not ideal, but it's too late now.

I really don't get this. When D has 10,000 programmers using it professionally, it's too late. But now it's more like 5 or 10. And they are all presumably aware that D2 is still undergoing some polish. So are the maybe a few hundred people that are using D for hobby projects. They are early adopters, and they know what that entails. I call bogus on the backwards compatibility argument. There's not a lot to be compatible with at this stage. Not compared to what D2 wants to become. As for Andrei's book using save with the parentheses: If D2 gains traction, I'm sure there will be a second edition of that book. And you already want to have the errata handy when using the book. I don't see what the big deal is, at least not compared to letting this stay in the language forever. save being a property is a stupid inconsistency. It's easy to fix, the cost is relatively low. The people using D2 now are all part of a community that want D to succeed, as am I. It's a change for the better, which I'm sure most current D2 users would agree with. How hard can it be?

I completely agree. One thing that most excited me about D at this stage, and buying in as an early adopter is that the developers WILL have the courage to make breaking changes if they're in the interest of creating a better language. I think every opportunity should be taken to make important breaking changes while the community is as small as it is. If the changes are reasonably trivial, then surely it doesn't trouble anyone THAT much to update their code. If they're using D2, surely they know it's still in the works. --20cf303b4147979a2604b3e48f62 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On 12 December 2011 14:24, torhu <span dir=3D"lt= r">&lt;no spam.invalid&gt;</span> wrote:<br><blockquote class=3D"gmail_quot= e" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"=
On 11.12.2011 22:24, Jonathan M Davis wrote:<br>

...<div class=3D"im"><br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> It was debated some time ago, and it ended up being a property. The fact th= at<br> save is an action verb and not a noun automatically disqualifies it as a<br=

tuck<br> with it at some point. As far as what the function does, I don&#39;t think = that<br> it&#39;s a problem that it&#39;s a property, but it&#39;s not named like a = property, so<br> the situation with regards to save is not ideal, but it&#39;s too late now.= <br> </blockquote> <br></div> I really don&#39;t get this. =C2=A0When D has 10,000 programmers using it p= rofessionally, it&#39;s too late. =C2=A0But now it&#39;s more like 5 or 10.= =C2=A0And they are all presumably aware that D2 is still undergoing some p= olish. So are the maybe a few hundred people that are using D for hobby pro= jects. =C2=A0They are early adopters, and they know what that entails. =C2= =A0I call bogus on the backwards compatibility argument. =C2=A0There&#39;s = not a lot to be compatible with at this stage. =C2=A0Not compared to what D= 2 wants to become.<br> <br> As for Andrei&#39;s book using save with the parentheses: =C2=A0If D2 gains= traction, I&#39;m sure there will be a second edition of that book. =C2=A0= And you already want to have the errata handy when using the book. =C2=A0I = don&#39;t see what the big deal is, at least not compared to letting this s= tay in the language forever.<br> <br> save being a property is a stupid inconsistency. =C2=A0It&#39;s easy to fix= , the cost is relatively low. =C2=A0The people using D2 now are all part of= a community that want D to succeed, as am I. It&#39;s a change for the bet= ter, which I&#39;m sure most current D2 users would agree with. =C2=A0How h= ard can it be?<br> </blockquote></div><br><div>I completely agree. One thing that most excited= me about D at this stage, and buying in as an early adopter is that the de= velopers WILL have the courage to make breaking changes if they&#39;re in t= he interest of creating a better language.</div> <div>I think every opportunity should be taken to make important breaking c= hanges while the community is as small as it is. If the changes are reasona= bly trivial, then surely it doesn&#39;t trouble anyone THAT much to update = their code. If they&#39;re using D2, surely they know it&#39;s still in the= works.</div> --20cf303b4147979a2604b3e48f62--
Dec 12 2011
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 12 December 2011 at 12:38:10 UTC, Jakob Ovrum wrote:
 Furthermore, there weren't even a way to enforce the property 
 syntax until lately, and it's still not enabled by default.

The real WTF is that someone decided property should be used for anything more than disambiguation.
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 14:46:17 UTC, Andrei Alexandrescu 
wrote:
 On 12/12/11 6:49 AM, Manu wrote:
 I think every opportunity should be taken to make important 
 breaking
 changes while the community is as small as it is.

Changing from r.save to r.save() is NOT an important change. It makes no semantic difference, marks no progress, and has no consequence. Insisting on the current property semantics was a sizeable mistake of this community, and I am sorry we gave into it. Andrei

The whole point of a property to begin with is to make it look like a field, which has two important implications: improves interchangeability with function access vs a field, and exploits the user's intuition associated with accessing fields. It is in light of the second consequence that it makes a difference. This is nothing new; the style guides for properties in C# operate on the same basic principle: if it looks like field access, it should behave like field access. If the programmer sees just "r.save", he doesn't know whether it's a field or a property, and he shouldn't need to know, it should be fast and cheap, and return a consistent value. As far as I know, this isn't always true for save, which means it breaks with the user's intuition. I don't know whether or not this is an important change, but it *does* have consequence, and the current property semantics (as enforced with -property) are definitely meaningful. The old situation where you could write complete nonsense code like `std.file.read = "foo.txt";` is far worse.
Dec 12 2011
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Monday, 12 December 2011 at 15:07:16 UTC, Jakob Ovrum wrote:
 The old situation where you could write complete nonsense code 
 like `std.file.read = "foo.txt";` is far worse.

If we start removing features because someone can use them when deliberately obfuscating their code, we might as well just abandon the whole idea of programming languages.
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 15:16:56 UTC, Adam D. Ruppe wrote:
 On Monday, 12 December 2011 at 15:07:16 UTC, Jakob Ovrum wrote:
 The old situation where you could write complete nonsense code 
 like `std.file.read = "foo.txt";` is far worse.

If we start removing features because someone can use them when deliberately obfuscating their code, we might as well just abandon the whole idea of programming languages.

Firstly, no feature is removed, it is changed, unless you consider calling completely property-unrelated functions with this syntax a feature. Secondly, it is an extreme example, more commonly occurring examples would be conflating property access with calling a member function with non-trivial complexity. With enforced property, the compiler helps the user write the most readable code for himself and more importantly, others.
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 15:14:02 UTC, Andrei Alexandrescu 
wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he 
 shouldn't need
 to know, it should be fast and cheap, and return a consistent 
 value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei

But save is an abstract interface function, its signature should reflect all possible implementations.
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 15:21:31 UTC, Andrei Alexandrescu 
wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 The old situation where you could
 write complete nonsense code like `std.file.read = "foo.txt";` 
 is far
 worse.

We could have defined a system much better than both. Andrei

I definitely agree. I think the current situation sucks. But I also think the previous situation sucks much, much more. (Unrelated side-note: I am using the web interface and I'm not well seasoned with using newsgroups, is there a better way to reply to multiple small posts than replying to each individually like I just did? I apologize if I'm being spammy.)
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 15:29:26 UTC, Jakob Ovrum wrote:
 On Monday, 12 December 2011 at 15:14:02 UTC, Andrei 
 Alexandrescu wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he 
 shouldn't need
 to know, it should be fast and cheap, and return a consistent 
 value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei

But save is an abstract interface function, its signature should reflect all possible implementations.

Adding on this: I have no problem with save being a property if it's meant/designed to be cheap etc. like with most struct ranges and slices. I also don't think the name is a problem; if you want to be really pedantic, "save" is actually a noun as well :P
Dec 12 2011
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 12 December 2011 at 16:09:03 UTC, Andrei Alexandrescu 
wrote:
 On 12/12/11 9:29 AM, Jakob Ovrum wrote:
 On Monday, 12 December 2011 at 15:14:02 UTC, Andrei 
 Alexandrescu wrote:
 On 12/12/11 9:07 AM, Jakob Ovrum wrote:
 If the programmer sees just "r.save", he
 doesn't know whether it's a field or a property, and he 
 shouldn't need
 to know, it should be fast and cheap, and return a 
 consistent value. As
 far as I know, this isn't always true for save

Why? Save does behave like a field for the vast majority of structs. Andrei

But save is an abstract interface function, its signature should reflect all possible implementations.

Same goes for many properties. Andrei

This is true, and many functions marked property arguably shouldn't be. I think it's a little like the reason std.container.SList doesn't have a `length` property: the O(n) complexity doesn't match the interface `length` exposes (although formalised only in documentation/convention, not code). If the standard library is allowed to assume `r.save` is a cheap operation, in the same fashion it's allowed to assume this(this) is cheap, then by all means, it makes sense as a property. The only remaining arguments against it are purely about the name, and I actually don't think that's relevant. And just like you can still make a computationally expensive this(this) when absolutely necessary, you can do the same with save. If most reasonable uses of save have trivial performance, it might as well be a property. I'm still a beginner with ranges, but by my understanding and by what some people made it sound like, reasonable uses of save include some which are non-trivial. If this is true, then removing property from save encourages people to think more about what using it might mean for the code they are writing, which is definitely important.
Dec 12 2011
prev sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Monday, 12 December 2011 at 15:32:05 UTC, Jakob Ovrum wrote:
 (Unrelated side-note: I am using the web interface and I'm not 
 well seasoned with using newsgroups, is there a better way to 
 reply to multiple small posts than replying to each 
 individually like I just did? I apologize if I'm being spammy.)

I don't think that's a problem. But to answer your question, no. The next best thing is to reply to the posts' common parent, or the thread's first post. Cite authors preserving the name/timestamp line and relevant quoted context.
Dec 13 2011
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 14 Dec 2011 13:50:09 -0000, Michel Fortin  
<michel.fortin michelf.com> wrote:

 On 2011-12-14 13:27:57 +0000, "Regan Heath" <regan netmail.co.nz> said:

 On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin
 <michel.fortin michelf.com> wrote:

 By "code patterns", you mean something like this?
  	struct Foo
 	{
 		int getBar();
 		void setBar(int);
 	}
  	void main()
 	{
 		Foo foo;
 		int a = foo.bar;  // calls getBar()
 		foo.bar = a;      // calls setBar(a)
 	}


I know the basics of the C# property syntax, but how do you take the address of the getter with it?

I hadn't given this a lot of thought. But, here goes.. :) The compiler (whatever the syntax used) will generate the get/set functions internally. So, it will technically be possible to take the address of both the getter and setter. Using my suggested syntax there is only 1 property name 'bar' and typically the function called is determined by the usage, e.g. Foo foo; int a = foo.bar; // getter called foo.bar = 4; // setter called So, what happens when we take the address.. Foo foo; int delegate(void) getter = &foo.bar; // takes the address of the getter void delegate(in) setter = &foo.bar; // takes the address of the setter I think that works, what do you reckon?
 And how do you define array-member properties like you can do with  
 functions?

I don't think we should call these "properties". What we're actually doing is adding members to built in types which can have any number of arguments and are therefore they're not strictly "properties". I think part of the confusion around properties comes from conflating these two ideas into one and calling them both "properties".
 And how do you disambiguate access those array members properties if two  
 imported modules define a property with the same name for an array?

I'd like to split the "adding array members" feature away from "properties" and look at it again, specifically due to problem cases like this. For example, in this case we could require the use of () for "adding array members" while for actual properties (user defined, on user defined types, using a c# like syntax or similar) we could require () not to be used. I think that pretty much avoids the whole can of worms, doesn't it? Regan -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 14 2011
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 14 Dec 2011 13:27:57 -0000, Regan Heath <regan netmail.co.nz>  =

wrote:

 On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin  =

 <michel.fortin michelf.com> wrote:

 On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu  =


 <SeeWebsiteForEmail erdani.org> said:

 We could have inferred property intention from the code pattern,  =



 without requiring any keyword. That solution (which was discussed an=



 rejected in this newsgroup) was miles ahead from the drivel of  =



  property we have now.

By "code patterns", you mean something like this? struct Foo { int getBar(); void setBar(int); } void main() { Foo foo; int a =3D foo.bar; // calls getBar() foo.bar =3D a; // calls setBar(a) }

Why not something similar to C# syntax... struct Foo { int bar // <- does DMD do lookahead? detect { instead of ; here a=

 trigger "property" parsing
    {
      get
      {
        return this;  // <- 'this' meaning the 'bar' member
      }
      set
      {
        this =3D value; // <- 'this' meaning the 'bar' member, 'value' =

 meaning the RHS of the "=A3instance.bar =3D <value>" statement
      }
    }
 }

 Regan

Apologies, there was a typo/mistake in the 'get' above. :) Regan -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Dec 14 2011
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Wed, 14 Dec 2011 02:36:43 -0000, Michel Fortin  =

<michel.fortin michelf.com> wrote:

 On 2011-12-13 23:08:43 +0000, Andrei Alexandrescu  =

 <SeeWebsiteForEmail erdani.org> said:

 We could have inferred property intention from the code pattern,  =


 without requiring any keyword. That solution (which was discussed and=


 rejected in this newsgroup) was miles ahead from the drivel of  =


  property we have now.

By "code patterns", you mean something like this? struct Foo { int getBar(); void setBar(int); } void main() { Foo foo; int a =3D foo.bar; // calls getBar() foo.bar =3D a; // calls setBar(a) }

Why not something similar to C# syntax... struct Foo { int bar // <- does DMD do lookahead? detect { instead of ; here and= = trigger "property" parsing { get { return value; // <- 'value' meaning the value of the 'bar' membe= r } set { this =3D value; // <- 'this' meaning the 'bar' member, 'value' me= aning = the RHS of the "=C2=A3instance.bar =3D <value>" statement } } } Regan
Dec 14 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 I'm not sure. How many times have you been in a place in life where you 
 had a const range on your hands, that's not an array? I haven't.

How many times I have used reduce or map on constant arrays in D2? Only few times, using a cast(). Now I am using them. Bye, bearophile
Dec 11 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 2:48 AM, bearophile wrote:
 Andrei Alexandrescu:

 I'm not sure. How many times have you been in a place in life
 where you had a const range on your hands, that's not an array? I
 haven't.

How many times I have used reduce or map on constant arrays in D2? Only few times, using a cast(). Now I am using them. Bye, bearophile

Emphasis added:
 I'm not sure. How many times have you been in a place in life where
 you had a const range on your hands, _that's_not_an_array_? I
 haven't.


Andrei
Dec 11 2011
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2011-12-11 07:16:28 +0000, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 On 12/10/11 5:20 PM, Michel Fortin wrote:
 Also seems strange to me that class references aren't included in that
 list, but then I though about how tail-const still doesn't work with
 objects. You'd need my const(Object)ref patch to make that work, and
 Walter hasn't taken time to look at it yet…

Have you continued to use your fork in daily work? If so, how does it pan out?

Sadly, I'm not using D in my daily work these days. It's mostly C++ and Objective-C. I'd like to replace those two with D using my DMD/Objective-C fork, but it's still incomplete (lacks memory management), and DMD having no 64-bit support on OSX was a showstopper -- in fact, it still is for DMD/Objective-C which still lacks support for Apple's modern Objective-C runtime used on the 64-bit side. And my inability to make D for Xcode work with Xcode 4 is hampering the effort too. When I start a new project I'll definitely try using D for it, but right now my D escapade is on hold. :-( -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 11 2011
parent Jacob Carlborg <doob me.com> writes:
On 2011-12-11 13:46, Michel Fortin wrote:
 On 2011-12-11 07:16:28 +0000, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> said:

 On 12/10/11 5:20 PM, Michel Fortin wrote:
 Also seems strange to me that class references aren't included in that
 list, but then I though about how tail-const still doesn't work with
 objects. You'd need my const(Object)ref patch to make that work, and
 Walter hasn't taken time to look at it yet…

Have you continued to use your fork in daily work? If so, how does it pan out?

Sadly, I'm not using D in my daily work these days. It's mostly C++ and Objective-C. I'd like to replace those two with D using my DMD/Objective-C fork, but it's still incomplete (lacks memory management), and DMD having no 64-bit support on OSX was a showstopper -- in fact, it still is for DMD/Objective-C which still lacks support for Apple's modern Objective-C runtime used on the 64-bit side. And my inability to make D for Xcode work with Xcode 4 is hampering the effort too.

It seems 64bit support will be available in the upcoming release (DMD for D1 has already been released). -- /Jacob Carlborg
Dec 12 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 01:16:28 Andrei Alexandrescu wrote:
 On 12/10/11 5:20 PM, Michel Fortin wrote:
 On 2011-12-10 21:47:13 +0000, Andrei Alexandrescu
 
 <SeeWebsiteForEmail erdani.org> said:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

It seems strange that if you implemented the exact same semantic as an a dynamic array or a pointer with a struct it wouldn't work. Basically, you're making a special case by giving two language-defined types characteristics that can't be replicated by user types. I'm not concerned that much, but I thought you worried about those things Andrei.

I do worry about those things, and this decision comes at the end of a long deliberation. There would be several aspects to discuss here. First, you are right that this confers built-in arrays a property that's not reproducible to user-defined types. And that's a bad thing. Second, that's not really as bad because the real issue is elsewhere. Remember the type "new T[]"? That was supposed to be the array type, which was to be supplanted by its range type, "T[]". After experimentation we decided to give up on that. Why? Because its benefits didn't justify the complication. So the issue we're solving here is that arrays and the ranges that crawl on them are represented by the same type. User-defined types have the option of defining distinct types for that. To truly confer user-defined types the same capability, we should define opPassByValue() which is implicitly invoked whenever an object is passed by value into a function. By default that is a do-nothing operator; for arrays it would do the cast thing (or, equivalently, invoke "[]" on the array), and people could define it to do whatever. We could do all that. The question is, is the added complexity justified?

I think that it's completely justified. We need a way to define tail-constness for ranges. Given const's transitiveness, it's very easy to end up in a situation where you have a const range, and having a means to get a tail-const version of that range would be very valuable. I don't know if opPassByValue is the best solution, but if not, we at least need a similar one. I'd say that in general, with opPassByValue, in the worst case, some people don't use it for their range types and those ranges don't work properly in cases that require tail-const. But those people who _do_ use it can benefit from it. It doesn't force anything on anyone. Yes, it's one more thing to learn about know about in D, but it _is_ something that a number of us have cited a need for for a while. - Jonathan M Davis
Dec 10 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 11 Dec 2011 06:16:33 -0500, Mehrdad <wfunction hotmail.com> wrote:

 On 12/11/2011 2:56 AM, David Nadlinger wrote:
 On 12/11/11 10:04 AM, Mehrdad wrote:
 On 12/11/2011 12:57 AM, Andrei Alexandrescu wrote:
 I think you should write:

 auto copy = this.save;

Ah good point, I forgot about that. Idk then. (You forgot the parentheses though. :P)

No, it's correct like that, save() is a property. Even though I recently updated Phobos to compile with -property enabled, I agree with Andrei here that in many cases there will be no perfect consensus whether a given member should be a property or not, thus potentially adding an extra source of complexity, or rather annoyance. David

Whoa what?! I didn't know save() is a property. In that case I stand corrected. :-) Nevertheless, I think that makes no sense. :P If something isn't a "property" of something else, it shouldn't be marked as such. But there are more reasons than that... I have found Microsoft's guidelines for C# to be great for general usage of the word property: http://msdn.microsoft.com/en-us/library/ms182181.aspx Specifically: "Properties should behave as if they are fields; if the method cannot, it should not be changed to a property. Methods are better than properties in the following situations: - Calling the method two times in succession creates different results. - The method performs a time-consuming operation. The method is perceivably slower than the time that is required to set or get the value of a field." Since both of these can be true for all but the most trivial kinds of ranges (e.g. file-system-related enumerators/ranges would very likely need to re-open a handle to a directory in order to traverse it, which is both relatively time-consuming AND returns a different result every time, and could even unexpectedly fail due to permission/connectivity issues), I don't think it makes sense for save() to be a property.

The very definition of save is that it's only defined if it's fast. So for example, a file range should not define save, it's an input range, not a forward range. IMO, the whole concept of save is crap anyways. I won't get into it again, search the NG archives if you want my opinion. -Steve
Dec 12 2011
prev sibling next sibling parent kenji hara <k.hara.pg gmail.com> writes:
Posted a test patch to realize the suggestion.
https://github.com/D-Programming-Language/dmd/pull/554

Kenji Hara

2011/12/11 kenji hara <k.hara.pg gmail.com>:
 OK. I agree to the suggestion.

 I've been afraid that increasing IFTI rule is making the language
 learning difficult.
 It comes from the experience from implementing inout deduction for
 template function.

 But also it is useful that removing top const when passing arguments by v=

 C++ precedent convinced me.

 Thanks.

 Kenji Hara

 2011/12/11 kenji hara <k.hara.pg gmail.com>:
 2011/12/11 Andrei Alexandrescu <SeeWebsiteForEmail erdani.org>:
 On 12/10/11 4:31 PM, kenji hara wrote:
 Treating whole constant arrays as ranges by automatically shedding the
 top-level const is good.
 But realizing it by language semantic change is definitely bad.It
 breaks IFTI rule, and adding special case will make difficult to learn
 language.

 Instead of language change, we can add specializations that receive
 non-ranges and convert them to ranges by removing top-level const.
 I believe that it is Phobos issue and is never the issue of language.

I should add there is precedent. C++ also removes top-level const when passing objects by value to templates. Deducing top-level const with pass-by-value is inherently nonsensical. Andrei

Hmm, it's for sure. ---- void print_type(int){} template <typename T> void f(T p) { =A0 =A0int n; =A0 =A0p =3D &n; =A0 =A0 // OK, head is mutable =A0 =A0//*p =3D 10; =A0// NG, tail is const =A0 =A0print_type(p); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Error: need explicit cast from int con=


 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// T is deduced as int const * =3D=3D top=


 }
 int main()
 {
 =A0 =A0int n;
 =A0 =A0int const * const p =3D &n;
 =A0 =A0f(p);
 =A0 =A0return 0;
 }

 Kenji


Dec 10 2011
prev sibling next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().
Dec 11 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well. Andrei
Dec 11 2011
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 11/12/2011 17:34, Andrei Alexandrescu a écrit :
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well. Andrei

I was thinking about sugesting this. So obviously, this is a +1 to me.
Dec 11 2011
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/11/2011 05:34 PM, Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well. Andrei

+1. This also reduces template bloat, because IFTI wont create different instantiations when passed T, immutable(T), const(T).
Dec 11 2011
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 12/11/2011 10:34 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects.

Those issues are inexistent. int and immutable(int) are implicitly convertible to each other.
 Another concern would be what would happen with primitives when they're inside
 of arrays. e.g.

 void func(T)(T[] arr)

 Having T lose its constness would be a big problem here.

Nobody suggested to do that.
Dec 11 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/11/2011 11:19 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 23:13:39 Timon Gehr wrote:
 On 12/11/2011 10:34 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the
 top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects.

Those issues are inexistent. int and immutable(int) are implicitly convertible to each other.

They may be implicitly convertible, but if you just outright stripped const and immutable from primitives, it would become impossible to instantiate a container which held const or immutable elements which were primitive.

MyContainer!(immutable(int)).
 Another concern would be what would happen with primitives when they're
 inside of arrays. e.g.

 void func(T)(T[] arr)

 Having T lose its constness would be a big problem here.

Nobody suggested to do that.

That may be, but depending on how the removal of const on primitives were applied, it would happen. We need to make sure that it _doesn't_ happen. My point was not that this is a horrible idea but rather that we need to make sure that it targets what it's supposed to target and does not have side effects that reduce D's current capabilities. - Jonathan M Davis

The qualifiers are stripped from the actual arguments, not from the template arguments.
Dec 11 2011
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/11/11 4:19 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 23:13:39 Timon Gehr wrote:
 On 12/11/2011 10:34 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the
 top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects.

Those issues are inexistent. int and immutable(int) are implicitly convertible to each other.

They may be implicitly convertible, but if you just outright stripped const and immutable from primitives, it would become impossible to instantiate a container which held const or immutable elements which were primitive.

Timon is right, there's no issue. Top-level qualifier would be stripped ONLY when passing by-value into a function. Andrei
Dec 11 2011
prev sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 11/12/2011 22:34, Jonathan M Davis a écrit :
 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects. Another concern would be what would happen with primitives when they're inside of arrays. e.g. void func(T)(T[] arr) Having T lose its constness would be a big problem here. Now, if we're talking only IFTI - such func(cast(immutable int)2) instantiates with int and func!(immutable int)(2) still instantiates with immutable int - and it's only for primitives by themselves (e.g. func above is unaffected), then it likely isn't a problem. But we need to really look at the side effects of trying to treat primitives as mutable in templates. And if you're going to do that with primitives, it also opens up the question as to what to do with structs which are value types. Should they be treated the same? In theory, I think that stripping const and immutable from primitives at the top level could be a nice thing to have, but I'd be very concerned about how that would be implemented and what it would affect. We risk losing valuable type information and breaking existing code if it's not done right. - Jonathan M Davis

I think you misunderstood the idea. The point was to remove constness of something passed by value, as long as it possible (native types, pointer (but not pointee), slices (but not what is in the slice), structs as long as they have no indirection in them). Has thoses are passed by value, the templated code will manipulate a copy of the data. So the original data can be immutable and the copied data can be mutable. This is not a big deal as theses data are differents ones.
Dec 11 2011
parent Max Samukha <maxsamukha gmail.com> writes:
On 12/12/2011 12:33 AM, deadalnix wrote:
 I think you misunderstood the idea. The point was to remove constness of
 something passed by value, as long as it possible (native types, pointer
 (but not pointee), slices (but not what is in the slice), structs as
 long as they have no indirection in them).

Then, should the rule be generalized to include any type that has no indirections to mutable data? struct S2 { immutable(int)* x; } struct S { string s; S2 s2; } void foo(T)(T s) if (!is(T == immutable)) { } immutable S s; foo(s); The argument is passed by value, the qualifier can be safely removed, so the call is rewritten to foo(cast(S)s); Any potential problems with that?
Dec 12 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects. Another concern would be what would happen with primitives when they're inside of arrays. e.g. void func(T)(T[] arr) Having T lose its constness would be a big problem here. Now, if we're talking only IFTI - such func(cast(immutable int)2) instantiates with int and func!(immutable int)(2) still instantiates with immutable int - and it's only for primitives by themselves (e.g. func above is unaffected), then it likely isn't a problem. But we need to really look at the side effects of trying to treat primitives as mutable in templates. And if you're going to do that with primitives, it also opens up the question as to what to do with structs which are value types. Should they be treated the same? In theory, I think that stripping const and immutable from primitives at the top level could be a nice thing to have, but I'd be very concerned about how that would be implemented and what it would affect. We risk losing valuable type information and breaking existing code if it's not done right. - Jonathan M Davis
Dec 11 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 11 Dec 2011 16:34:34 -0500, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects. Another concern would be what would happen with primitives when they're inside of arrays. e.g. void func(T)(T[] arr) Having T lose its constness would be a big problem here.

T does not lose its constness here. const(U[]) would go to const(U)[], which would then set T = const(U).
 Now, if we're talking only IFTI - such func(cast(immutable int)2)  
 instantiates
 with int and func!(immutable int)(2) still instantiates with immutable  
 int -
 and it's only for primitives by themselves (e.g. func above is  
 unaffected),
 then it likely isn't a problem. But we need to really look at the side  
 effects
 of trying to treat primitives as mutable in templates.

We are talking only IFTI. Specifically, we are saying, for purposes of implying template parameters during IFTI, strip all the qualifiers from the pieces passed by value, as long as it doesn't affect any pieces passed by reference. I bet doing this one thing would instantly trim at least 10k of bloat from an executable. I'm looking at you, writeln.
 And if you're going to do that with primitives, it also opens up the  
 question
 as to what to do with structs which are value types. Should they be  
 treated
 the same?

Yes. -Steve
Dec 12 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 23:13:39 Timon Gehr wrote:
 On 12/11/2011 10:34 PM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 10:34:40 Andrei Alexandrescu wrote:
 On 12/11/11 9:46 AM, dsimcha wrote:
 On 12/10/2011 4:47 PM, Andrei Alexandrescu wrote:
 We decided to fix this issue by automatically shedding the
 top-level
 const when passing an array or a pointer by value into a function.

Really silly question: Why not do the same for primitives (int, float, char, etc.) or even structs without indirection? I've seen plenty of code that blows up when passed an immutable double because it tries to mutate its arguments. About 1.5 years ago I fixed a bug like this in std.math.pow().

Yes, that would be good to do as well.

Actually, that could be a problem for some stuff. It might be an acceptable problem, but it creates a problem nonetheless. What about containers? You can have arrays with immutable elements, but if you made it so that immutable int and int were the same as far as templates were concerned, then it would be impossible to have a container which held immutable elements. How big of a problem that is, I don't know, but I'd be concerned about some of the side effects.

Those issues are inexistent. int and immutable(int) are implicitly convertible to each other.

They may be implicitly convertible, but if you just outright stripped const and immutable from primitives, it would become impossible to instantiate a container which held const or immutable elements which were primitive.
 Another concern would be what would happen with primitives when they're
 inside of arrays. e.g.
 
 void func(T)(T[] arr)
 
 Having T lose its constness would be a big problem here.

Nobody suggested to do that.

That may be, but depending on how the removal of const on primitives were applied, it would happen. We need to make sure that it _doesn't_ happen. My point was not that this is a horrible idea but rather that we need to make sure that it targets what it's supposed to target and does not have side effects that reduce D's current capabilities. - Jonathan M Davis
Dec 11 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property? - Jonathan M Davis
Dec 12 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 12 Dec 2011 19:00:35 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

Wait, are we talking about property or .save? -Steve
Dec 12 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Tuesday, December 13, 2011 02:28:29 torhu wrote:
 It's actually not 'save' being a noun that's the problem. I just
 thought of a counter-example:
 
 ---
 struct Foo {
 // the data
 Bar data[];
 
 // save data on shutdown?
  property bool save() { return save_; }
  property bool save(bool shouldShave) { return save_ = shouldSave; }
 
 private:
 bool save_;
 }
 ---
 Not meant to be a realistic example, but save is fine as a property here.

You can pretty much always come up with another function with a completely different purpose wit the same name. Personally, the _only_ issue that I have with save is the fact that it's a property. The name save works well enough, and I can't think of anything that's better. - Jonathan M Davis
Dec 12 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, December 12, 2011 18:00:35 Andrei Alexandrescu wrote:
 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

So, you prefer the situation where any function with no arguments can be used as a getter and any function with a single argument can be used as a setter? Not only is that incredibly lax, but it makes it impossible to be able to switch between public member variables and property functions without breaking code, which is supposed to be one of the main purposes of property functions in programming languages in general. With property, such a switch _is_ possible (aside from a few corner cases such as when someone takes the address of a public member variable). It will also lead to a consistent use of parentheses instead of having the syntax used with a function varying wherever it's used. Sure, you then get arguments over whether a function should be a property or not, but that's generally just part of the discussion of how to name a function, and with that, there's always risk that someone will disagree later, so I'm not sure that it makes the situation all that much worse, and IMHO it's well worth the advantage of having proper properties. What D had was better than nothing, but it was inconsistent and lacked the ability to swap member variables and property functions, which made it far worse than property IMHO. - Jonathan M Davis
Dec 13 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Tuesday, December 13, 2011 14:02:51 Andrei Alexandrescu wrote:
 On 12/13/11 10:32 AM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 18:00:35 Andrei Alexandrescu wrote:
 On 12/12/11 1:12 PM, Jonathan M Davis wrote:
 On Monday, December 12, 2011 08:46:18 Andrei Alexandrescu wrote:
 Insisting on the current property semantics was a sizeable mistake
 of
 this community, and I am sorry we gave into it.

Aside from the fact that the behavior of -property isn't the default, what's the problem with property?

Other than it being completely useless, requiring more rote memorization, and fomenting time-wasting discussion? None.

So, you prefer the situation where any function with no arguments can be used as a getter and any function with a single argument can be used as a setter?


I'm not saying that those are the only choices, but you seem to think that the current situation is worse than what we had before, which I don't understand. The current situation looks all around better to me. - Jonathan M Davis
Dec 13 2011
prev sibling next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu 
wrote:
 There's a phrase in Romanian that quite applies: "From the lake 
 into the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.
Dec 13 2011
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Sunday, December 11, 2011 02:05:08 Andrei Alexandrescu wrote:
 On 12/11/11 1:30 AM, Jonathan M Davis wrote:
 On Sunday, December 11, 2011 01:16:28 Andrei Alexandrescu wrote:
 To truly confer user-defined types the same capability, we should
 define
 opPassByValue() which is implicitly invoked whenever an object is
 passed
 by value into a function. By default that is a do-nothing operator;
 for
 arrays it would do the cast thing (or, equivalently, invoke "[]" on
 the
 array), and people could define it to do whatever. We could do all
 that.
 The question is, is the added complexity justified?

I think that it's completely justified. We need a way to define tail-constness for ranges. Given const's transitiveness, it's very easy to end up in a situation where you have a const range, and having a means to get a tail-const version of that range would be very valuable. I don't know if opPassByValue is the best solution, but if not, we at least need a similar one.

I'm not sure. How many times have you been in a place in life where you had a const range on your hands, that's not an array? I haven't.

I tend to avoid const ranges precisely because they pretty much never work. I'd use them more if a tail-const version of them were easily obtainable - _especially_ if they worked the same way that arrays are going to be working with IFTI. Also, as std.container is filled out, the number of ranges which aren't arrays will definitely increase. Right now, they're almost always arrays or arrays wrapped by other ranges, and often you have to call array on the wrapped ones anyway, so a large portion of the time at this point, ranges are arrays. And while that will still hold to some extent, that should lessen as std.container is fleshed out. And that means that issues with const ranges will increase. Also, it's completely inconsistent that you can pass a const array to a range- based function and have it work but not a const user-defined range. It may be that we could get the compiler to figure it out based on slicing (assuming that opSlice returns the same type as the range itself aside from constness - otherwise passing containers to range-based functions would instantiate on the containers, which would cause issues, especially since it would be the container being passed, not a slice). And if we could do that, then I don't think that there would be any need for opPassByValue, but without a solution along those lines, we're going to have people complaining about not being able to pass const value-type ranges to range-based functions. And as fantastic as template constraints are, they don't make it immediately obvious why the type failed - certainly nothing as nice as "Error: find does not work with a const range." I do think that there is merit in seeing whether we can get the compiler to use opSlice to do what opPassByValue would do, but I also think that we should do something about this issue, or const ranges will forever be a problem. The only reasons that I don't run into the issue more is because I avoid const with ranges and with such a sparse std.container, so many ranges are arrays. - Jonathan M Davis
Dec 13 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 I tend to avoid const ranges precisely because they pretty much never work. 
 I'd use them more if a tail-const version of them were easily obtainable -

This is what I was trying to answer to Andrei :-) Bye, bearophile
Dec 14 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 13 Dec 2011 18:08:43 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 12/13/11 5:14 PM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu  
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length) 2. Complicating the language (proof: this discussion) 3. Another thing to learn. 4. Another thing for tools to process. I don't think the syntax sugar it provides counts for anything really. The ability to refactor member look ups is nice, but I find that this rarely occurs in practice and even when it occurs, it's not hard to replace obj.field with obj.field() or obj.getField(). The costs far outweigh the benefits IMO.

We could have inferred property intention from the code pattern, without requiring any keyword. That solution (which was discussed and rejected in this newsgroup) was miles ahead from the drivel of property we have now. I noticed there's a tunnel vision phenomenon when it comes to keyword-based solutions: once a special notation is on the table, there's no appreciation for anything else. That's what happened with lazy (another design misfire I'm very unhappy about) and with property. I literally feel my heart rate getting up when I think of them.

property wasn't my first choice, there were probably a dozen proposals on the table. I liked the C# version the best: http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP4 But here is the phenomenon I noticed: N different solutions get proposed, and are debated by the community. Walter is very vocal about what he doesn't like, but silent on other aspects (presumably because he is considering them?) All of a sudden Walter picks a solution, then posts a thread to flesh out the details. After that, it's hard to change his mind. For the property debate, looking back through the newsgroups, it looks like Walter and you came up with a solution that nobody had proposed and nobody liked. Then somehow property was chosen. Not sure how that happened or what the convincing argument was. But you will notice in that discussion that many of the solutions did not involve keywords, and all were given equal air time (I don't see tunnel vision). Thread: http://dfeed.kimsufi.thecybershadow.net/discussion/post/h53g3i$elk$1 digitalmars.com I personally don't mind property, even if there are better solutions. It's not as horrible as you say IMO. -Steve
Dec 14 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I don't mind  property, usually I just create one property block for a
class, e.g.:
 property
{
    // funcs..
}
Dec 14 2011
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 14 Dec 2011 15:39:55 -0500, Peter Alexander  
<peter.alexander.au gmail.com> wrote:

 On 14/12/11 8:16 AM, Timon Gehr wrote:
 On 12/14/2011 12:35 AM, Peter Alexander wrote:
 On 13/12/11 11:11 PM, Timon Gehr wrote:
 On 12/14/2011 12:14 AM, Peter Alexander wrote:
 On 13/12/11 10:17 PM, Vladimir Panteleev wrote:
 On Tuesday, 13 December 2011 at 21:10:22 UTC, Andrei Alexandrescu
 wrote:
 There's a phrase in Romanian that quite applies: "From the lake  
 into
 the well".

I believe the English version is "Out of the frying pan, into the fire" :) Inconsequential space-filler opinion: I am OK with property, mainly because it's a common feature among PLs, it's better than nothing, and don't know better solutions.

In my opinion, it's not better than nothing. What it gives you: 1. A bit of syntactic sugar. 2. The ability to refactor member look up easily. What it costs: 1. Overloads syntax. a. obj.field can now be an arbitrary function call. b. May have arbitrary cost (e.g. T[].length)

??? T[].length is a field access, not a property function. It takes a small constant amount of time.

Assigning to the length of an array may reallocate it, which is not a small, nor constant amount of time. int[] a; ... a.length = n; // may invoke a GC allocation + O(n) memcpy

OK, I see, thanks. I don't think it is problematic in this particular case though.

Well, it is a little. It makes it difficult to scan code looking for GC allocations, or even scan code looking for inefficiencies. Obviously I know now that I have to look for .length assignments on arrays, but it can be quite horrific when looking at code that uses third party libraries that you aren't familiar with. An example of this I encountered in practice was in Unity3D's libraries. http://unity3d.com/support/documentation/ScriptReference/WWW-texture.html The WWW class has a 'texture' property. A small sentence in the middle of its documentation reveals the horror. "Each invocation of texture property allocates a new Texture2D." That's right. Every time you read WWW.texture, it allocates a large chunk of memory. In my particular case, I was copying the pixels from the texture into another array, something like this: WWW www = ...; for (int i = 0; i < www.texture.width; ++i) for (int j = 0; j < www.texture.height; ++j) buffer[i][j] = www.texture.GetPixel(i, j); For a small 100x100 texture, that code allocates over 10,000, 100x100 textures. Luckily, that was horrific enough to prompt me to investigate, but a less obvious problem would have likely slipped past me unnoticed.

Yes, but length as a read property does not allocate anything (nor does reducing the length). In fact, length as a read property reduces to a field access (it is a language builtin, after all). Would you expect that setting the length of an array to a *larger* size would not allocate? Your example shows something that doesn't look like it should be costly, but it actually is. Expanding length *looks* costly (and it is). You do have a point that it shouldn't necessarily be a property. I also don't think dup, reverse, or sort should be array properties. But these are pieces of the language that have been there forever. To change them now would be disruptive for very little gain. -Steve
Dec 14 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:

 I also don't think dup, reverse, or sort should be array properties.  But
these  
 are pieces of the language that have been there forever.  To change them  
 now would be disruptive for very little gain.

sort and reverse properties will be deprecated and later removed. Bye, bearophile
Dec 14 2011