September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | "Andrei Alexandrescu" wrote > Steven Schveighoffer wrote: >> "Andrei Alexandrescu" wrote >>> Steven Schveighoffer wrote: >>>> "Andrei Alexandrescu" wrote >>>>>> P.S. If src.next() is too lengthy, why not just adopt ++src? >>>>> Because people (in wake of the recently introduced array operations) may legitimately expect that to mean "increment all elements of src". >>>> So in one case, you believe people's assumptions aren't important, i.e. an assumption that .next without parens will not change anything on the object, yet in another case you believe people's assumptions are the main argument. This doesn't sound consistent. >>> Of course it is. One expectation has to do with operational consistency (albeit a tad far-fetched), the other has to do with being used to a mistaken decision in the C language design. >> >> You are assuming that the C language decision to require parentheses for all functions was a design mistake. I would argue that the design was on purpose and correctly served that purpose. The purpose was to remove ambiguity when faced with understanding code without all the context. > > I have stated my assumption and its basis. Forgive me, but I must have missed it. I saw only your assumption (or supposition) that the C designers made a mistake. > What is the basis of yours? I don't have any actual proof that they did this on purpose, I wasn't working at Bell labs when C was invented, in fact, I don't even think I was born ;) But it makes logical sense, and still does. If you want to call a function, you have to use parentheses. If you want to access the function address, no parentheses. It follows other design decisions they made: pointers: Access what it's pointing to, use ->, get address it's pointing to, use symbol alone. >> But that isn't even the questioned practice here. C designers didn't even come across the question of whether an accessor-property should imply no changes to the object, because they don't have properties. The real problem is that no matter how you define next(), you can use it in a way which makes it appear like an accessor, not a function which modifies the object. The source of the problem is D's lack of expressiveness, where I cannot define whether a function cannot be used as a property. > > I understand your argument, but it hinges on its own definitions and assumptions. You define "accessor" and then complain that something looks like one unexpectedly. Well in some languages a.b does not change anything. In others it does. What gives? There is no hard-fast rule that an accessor cannot change things. The issue is that since any function can be an accessor you can't even try to adopt a policy in your library that says 'accessors will not change things'. Because you can't define which functions can be used as accessors and which ones can't. I WANT a.b to be able to be a function call, I just want to specify which functions can be called that way, and which ones cannot, so I can define how my library behaves and someone reading code that uses it will know that my rules were followed. > >> Even with a true property definition syntax, you cannot prevent someone from changing an object while inside an accessor, that should be defined by the constancy of the object in question. But indicating that it is preferred to use the property-style means to access the next() member function seems to be misleading to some people. > > So that further weakens your argument. How so? I'm not talking about whether or not the compiler should restrict the developer on being able to make changes in accessors. That is what const is for. I'm talking about being able to specify a coding convention that says 'accessors shall not change things'. Currently, there's no way to prevent any function from being used as an accessor, so a library developer cannot enforce this rule to people using his library. >> The problem I have with your argument is how you used one case to say 'this is misleading to people, so it's not a valid solution', and in another case say 'it's only misleading because you are used to it, that doesn't matter.' The assumption of which people are important to please is the issue. I understand you can't please everyone, but you shouldn't use the 'people won't like it' argument without real evidence or proof. > > I agree that ++array may not be easily confused with ++array[]. The situation I am trying to help is improve on a mistake in the C language design that we got so used to, we actually think it's the right thing. According to comments on this newsgroup, and some quoted bug reports, many believe that it's the D methodology of not requiring parentheses that is a mistake. As far as I can tell, it's a matter of opinion, not fact. >>>> Not that I care too much :) I am also in the camp of 'defined properties should be a language feature,' but I admit to using D-properties quite often. >>>> >>>> The two things that bug me the most about D property syntax: >>>> >>>> stuff like this: >>>> >>>> x; >>>> >>>> What the hell does this mean? It looks like it does nothing. But it could be a function call. If explicit properties were required, and x was defined as a function, not a property, then x; would be a syntax error. >>> And what would be the advantage? I routinely use writeln; without feeling it makes for inferior style. >> >> The advantage is not to you, it is to the reader of your code. writeln; is a complete misuse of property syntax, and IMO should not be allowed. writeln is not a property, and shouldn't be used like a property. > > Aside from just saying it, do you have any substantive argument? The arguments have been made. As I stated, it's my opinion. >> I routinely use Tango's Stdout.newline; which I admit goes against what I am saying, but it's because I know what Stdout.newline does, and that it is a function. I would gladly change everything to Stdout.newline() if it was required. > > To what benefit? You seem to be using it today, and that makes your own style incongruent with your argument, yet surely you'd change the style in an iffy if you thought it has serious drawbacks. The benefit is clarity. Stdout.newline; looks like a property or field of Stdout. By itself, it's somewhat jarring, but it's somewhat clear that newline is a function if you know the rules of D. However, something like this isn't so clear: Stdout.newline.formatln("Hi there {}", var); Is newline a property of Stdout, on which I'm calling formatln, or is newline a function that I'm calling, and then using the result of that function to call formatln? Compare with: Stdout.newline().formatln("Hi there {}", var); There is no ambiguity. newline is clearly a function, not a property. My personal habits are ones I would like to change. I'd prefer to write clearer code, not shorter code. I consider writing Stdout.newline; a bad habit fostered by the lax function calling rules of D ;) > >> The problem is not that you or anyone might forget that writeln is a function and not a property, the problem is when you start using the property syntax to call functions that aren't so standard, someone reading the code will be confused as to what the code is supposed to do. >> >> The advantage is, you are able to define how a symbol behaves, what the rules are for using it. It makes for clearer code. > > I am not sure. Neither answer is definitely the 'correct' one, there are tradeoffs between both styles. I like the how D properties are so easy to write, and can be accessed like functions when needed, but I don't like how you can have weird looking code to have to decipher. Having written properties in C# quite a bit, I prefer that method of requiring a formal property definition. -Steve |
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Sun, 28 Sep 2008 22:53:13 -0500,
Andrei Alexandrescu wrote:
> Bill Baxter wrote:
> > The rule is trivial, you may say. But how about co-variant return types? If FooSub is a subclass of Foo, then is it ok for the getter to return one and setter to take the other? Or vice versa? Or how about implicit conversions. If my getter takes a long, but my setter returns an int, is that ok? How do const variations fit in? Probably there's a way to fit those all neatly in an automatic rule (or just disallow them), but it just makes the rule longer and even harder to keep in mind (or cuts off functionality people may need).
>
> Yah, I was thinking of all these and then some more while I was posting.
>
> I think it's another duck typing thing. If you can call:
>
> entity.prop(entity.prop);
>
> then you can consider prop a property, period. Entity could be anything that allows the dot member access (object, class, struct, union, template, or module). Given that there is no global scope in D, that takes care of everything. I think it's really hard to get any simpler than that.
D has a simple rule for property methods. This rule has side effects. If the side effects are so bad that a hack is required to counter them, then the rule should be replaced with a better one. Otherwise your hack will inevitably introduce new, less obvious side effects than those it were supposed to fight, and will finally require other hacks.
struct Range
{
ref int head() {...}
}
Range r;
r.head = 5; // error
|
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer wrote: > "Andrei Alexandrescu" wrote >> Steven Schveighoffer wrote: >>> "Andrei Alexandrescu" wrote >>>> Steven Schveighoffer wrote: >>>>> "Andrei Alexandrescu" wrote >>>>>>> P.S. If src.next() is too lengthy, why not just adopt ++src? >>>>>> Because people (in wake of the recently introduced array operations) may legitimately expect that to mean "increment all elements of src". >>>>> So in one case, you believe people's assumptions aren't important, i.e. an assumption that .next without parens will not change anything on the object, yet in another case you believe people's assumptions are the main argument. This doesn't sound consistent. >>>> Of course it is. One expectation has to do with operational consistency (albeit a tad far-fetched), the other has to do with being used to a mistaken decision in the C language design. >>> You are assuming that the C language decision to require parentheses for all functions was a design mistake. I would argue that the design was on purpose and correctly served that purpose. The purpose was to remove ambiguity when faced with understanding code without all the context. >> I have stated my assumption and its basis. > > Forgive me, but I must have missed it. I saw only your assumption (or supposition) that the C designers made a mistake. My post on 25 Sep 2008 17:58:52 -0500 mentions: "One principle that I consider universal is that a language should minimize the number of syntactic constructs that are semantically and/or pragmatically meaningless. Another that I also consider universal is that the more frequently-used constructs should be given syntactic priority over the less-used constructs, particularly when the latter are also at risk of breaking the first principle." >> What is the basis of yours? > > I don't have any actual proof that they did this on purpose, I wasn't working at Bell labs when C was invented, in fact, I don't even think I was born ;) > > But it makes logical sense, and still does. If you want to call a function, you have to use parentheses. If you want to access the function address, no parentheses. This is no logic. Your proof is just stating the conclusion. It's a logical fallacy called proof by assertion. http://en.wikipedia.org/wiki/Proof_by_assertion > It follows other design decisions they made: > > pointers: Access what it's pointing to, use ->, get address it's pointing to, use symbol alone. This is wrong too. If you use symbol alone, you are not getting its address. You are referring the pointer, which is an address. It would have been consistent with other design decisions if referring a variable alone would take its address. >>> But that isn't even the questioned practice here. C designers didn't even come across the question of whether an accessor-property should imply no changes to the object, because they don't have properties. The real problem is that no matter how you define next(), you can use it in a way which makes it appear like an accessor, not a function which modifies the object. The source of the problem is D's lack of expressiveness, where I cannot define whether a function cannot be used as a property. >> I understand your argument, but it hinges on its own definitions and assumptions. You define "accessor" and then complain that something looks like one unexpectedly. Well in some languages a.b does not change anything. In others it does. What gives? > > There is no hard-fast rule that an accessor cannot change things. The issue is that since any function can be an accessor you can't even try to adopt a policy in your library that says 'accessors will not change things'. Because you can't define which functions can be used as accessors and which ones can't. Const takes care of that. > I WANT a.b to be able to be a function call, I just want to specify which functions can be called that way, and which ones cannot, so I can define how my library behaves and someone reading code that uses it will know that my rules were followed. Why do you want to specify that? What difference does it make? Why would you complicate the language just for a hypothetical convention that's not even compiler-checked? >>> Even with a true property definition syntax, you cannot prevent someone from changing an object while inside an accessor, that should be defined by the constancy of the object in question. But indicating that it is preferred to use the property-style means to access the next() member function seems to be misleading to some people. >> So that further weakens your argument. > > How so? I'm not talking about whether or not the compiler should restrict the developer on being able to make changes in accessors. That is what const is for. I'm talking about being able to specify a coding convention that says 'accessors shall not change things'. Currently, there's no way to prevent any function from being used as an accessor, so a library developer cannot enforce this rule to people using his library. I personally think it's great that any function can be used as an accessor. I'd be convinced otherwise presented a good arguments against it. What problems are you foreseeing with not being able to enforce against not using ()? >>> The problem I have with your argument is how you used one case to say 'this is misleading to people, so it's not a valid solution', and in another case say 'it's only misleading because you are used to it, that doesn't matter.' The assumption of which people are important to please is the issue. I understand you can't please everyone, but you shouldn't use the 'people won't like it' argument without real evidence or proof. >> I agree that ++array may not be easily confused with ++array[]. The situation I am trying to help is improve on a mistake in the C language design that we got so used to, we actually think it's the right thing. > > According to comments on this newsgroup, and some quoted bug reports, many believe that it's the D methodology of not requiring parentheses that is a mistake. As far as I can tell, it's a matter of opinion, not fact. > >>>>> Not that I care too much :) I am also in the camp of 'defined properties should be a language feature,' but I admit to using D-properties quite often. >>>>> >>>>> The two things that bug me the most about D property syntax: >>>>> >>>>> stuff like this: >>>>> >>>>> x; >>>>> >>>>> What the hell does this mean? It looks like it does nothing. But it could be a function call. If explicit properties were required, and x was defined as a function, not a property, then x; would be a syntax error. >>>> And what would be the advantage? I routinely use writeln; without feeling it makes for inferior style. >>> The advantage is not to you, it is to the reader of your code. writeln; is a complete misuse of property syntax, and IMO should not be allowed. writeln is not a property, and shouldn't be used like a property. >> Aside from just saying it, do you have any substantive argument? > > The arguments have been made. As I stated, it's my opinion. > >>> I routinely use Tango's Stdout.newline; which I admit goes against what I am saying, but it's because I know what Stdout.newline does, and that it is a function. I would gladly change everything to Stdout.newline() if it was required. >> To what benefit? You seem to be using it today, and that makes your own style incongruent with your argument, yet surely you'd change the style in an iffy if you thought it has serious drawbacks. > > The benefit is clarity. > > Stdout.newline; > > looks like a property or field of Stdout. By itself, it's somewhat jarring, but it's somewhat clear that newline is a function if you know the rules of D. But you do use Stdout.newline and the alleged loss in clarity doesn't seem to be phasing you. > However, something like this isn't so clear: > > Stdout.newline.formatln("Hi there {}", var); > > Is newline a property of Stdout, on which I'm calling formatln, or is newline a function that I'm calling, and then using the result of that function to call formatln? Compare with: > > Stdout.newline().formatln("Hi there {}", var); > > There is no ambiguity. newline is clearly a function, not a property. There is no ambiguity either case. You evaluate Stdout.newline. The evaluation yields a value of some type. Then you evaluate formatln against that value. What's missing is the unstated assumption that "if it doesn't have trailing parens, it must be a field". I don't think it is useful to be making that assumption. > My personal habits are ones I would like to change. I'd prefer to write clearer code, not shorter code. I consider writing Stdout.newline; a bad habit fostered by the lax function calling rules of D ;) Giving the choice of shorter vs. clearer is a false choice, another fallacy if I remember correctly. Put another way, wouldn't you at best write shorter and clearer code? >>> The problem is not that you or anyone might forget that writeln is a function and not a property, the problem is when you start using the property syntax to call functions that aren't so standard, someone reading the code will be confused as to what the code is supposed to do. >>> >>> The advantage is, you are able to define how a symbol behaves, what the rules are for using it. It makes for clearer code. >> I am not sure. > > Neither answer is definitely the 'correct' one, there are tradeoffs between both styles. I like the how D properties are so easy to write, and can be accessed like functions when needed, but I don't like how you can have weird looking code to have to decipher. Having written properties in C# quite a bit, I prefer that method of requiring a formal property definition. I am not seeing weird code that is there to be deciphered. There is this "writeln = 3" weirdness that I'd love to weed out, but all this required trailing parens stuff simply doesn't have any good argument working in its favor. Andrei |
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sergey Gromov | Sergey Gromov wrote:
> Sun, 28 Sep 2008 22:53:13 -0500,
> Andrei Alexandrescu wrote:
>> Bill Baxter wrote:
>>> The rule is trivial, you may say. But how about co-variant return
>>> types? If FooSub is a subclass of Foo, then is it ok for the getter
>>> to return one and setter to take the other? Or vice versa? Or how
>>> about implicit conversions. If my getter takes a long, but my setter
>>> returns an int, is that ok? How do const variations fit in? Probably
>>> there's a way to fit those all neatly in an automatic rule (or just
>>> disallow them), but it just makes the rule longer and even harder to
>>> keep in mind (or cuts off functionality people may need).
>> Yah, I was thinking of all these and then some more while I was posting.
>>
>> I think it's another duck typing thing. If you can call:
>>
>> entity.prop(entity.prop);
>>
>> then you can consider prop a property, period. Entity could be anything that allows the dot member access (object, class, struct, union, template, or module). Given that there is no global scope in D, that takes care of everything. I think it's really hard to get any simpler than that.
>
> D has a simple rule for property methods. This rule has side effects. If the side effects are so bad that a hack is required to counter them,
> then the rule should be replaced with a better one. Otherwise your hack will inevitably introduce new, less obvious side effects than those it were supposed to fight, and will finally require other hacks.
>
> struct Range
> {
> ref int head() {...}
> }
> Range r;
> r.head = 5; // error
A function can return an object that allows assignment even today with opAssign.
I said "If you can call: entity.prop(entity.prop); then you can consider prop a property, period." I did not say "If and only if".
Andrei
|
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Mon, 29 Sep 2008 12:23:58 -0500, Andrei Alexandrescu wrote: > Sergey Gromov wrote: > > D has a simple rule for property methods. This rule has side effects. If the side effects are so bad that a hack is required to counter them, then the rule should be replaced with a better one. Otherwise your hack will inevitably introduce new, less obvious side effects than those it were supposed to fight, and will finally require other hacks. > > > > struct Range > > { > > ref int head() {...} > > } > > Range r; > > r.head = 5; // error > > A function can return an object that allows assignment even today with opAssign. Today the compiler tries to call Range.head with one argument and fails. Another side effect needs hacking. > I said "If you can call: entity.prop(entity.prop); then you can consider prop a property, period." I did not say "If and only if". |
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> Sergey Gromov wrote:
>> Sun, 28 Sep 2008 22:53:13 -0500,
>> Andrei Alexandrescu wrote:
>>> Bill Baxter wrote:
>>>> The rule is trivial, you may say. But how about co-variant return
>>>> types? If FooSub is a subclass of Foo, then is it ok for the getter
>>>> to return one and setter to take the other? Or vice versa? Or how
>>>> about implicit conversions. If my getter takes a long, but my setter
>>>> returns an int, is that ok? How do const variations fit in? Probably
>>>> there's a way to fit those all neatly in an automatic rule (or just
>>>> disallow them), but it just makes the rule longer and even harder to
>>>> keep in mind (or cuts off functionality people may need).
>>> Yah, I was thinking of all these and then some more while I was posting.
>>>
>>> I think it's another duck typing thing. If you can call:
>>>
>>> entity.prop(entity.prop);
>>>
>>> then you can consider prop a property, period. Entity could be anything that allows the dot member access (object, class, struct, union, template, or module). Given that there is no global scope in D, that takes care of everything. I think it's really hard to get any simpler than that.
>>
>> D has a simple rule for property methods. This rule has side effects. If the side effects are so bad that a hack is required to counter them,
>> then the rule should be replaced with a better one. Otherwise your hack will inevitably introduce new, less obvious side effects than those it were supposed to fight, and will finally require other hacks.
>>
>> struct Range
>> {
>> ref int head() {...}
>> }
>> Range r;
>> r.head = 5; // error
>
> A function can return an object that allows assignment even today with opAssign.
>
> I said "If you can call: entity.prop(entity.prop); then you can consider prop a property, period." I did not say "If and only if".
>
>
> Andrei
Just wondering... What about opCall's? Will it be considered while evaluating "entity.prop(entity.prop)"? (I hope not :p, and an object S won't be evaluated to S() := S.opCall() anyway.)
struct A {
invariant void opCall(invariant(A) x) { writeln('hi'); }
}
struct B {
invariant(A) a;
}
b.a(b.a) compiles but b.a = b.a does not make sense (b.a is not mutable).
|
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> Don wrote:
>> Andrei Alexandrescu wrote:
>>> Sergey Gromov wrote:
>>>> In article <gbjihf$2803$1@digitalmars.com>, frank@youknow.what.todo.interNETz says...
>>>>> Andrei Alexandrescu wrote:
>>>>>> Steven Schveighoffer wrote:
>>>>>>> You are assuming that the C language decision to require parentheses for all functions was a design mistake. I would argue that the design was on purpose and correctly served that purpose. The purpose was to remove ambiguity when faced with understanding code without all the context.
>>>>>> I have stated my assumption and its basis. What is the basis of yours?
>>>>> Yum. I think the problem is that when C was designed, K&R didn't consider
>>>>> the use of classes with properties using getter and setter methods.
>>>>> Therefore, it made sense to have the naked function name denote the
>>>>> function pointer, and make braces following an identifier the mark of a
>>>>> function call. I initially had some trouble accepting the explicit & in D
>>>>> to get the function pointer myself.
>>>>> I wouldn't go so far as to call that property of C a design mistake in
>>>>> light of the actual intensions of K&R. But I definitely would defend
>>>>> the choice of a language designer to change that feature in light of
>>>>> more modern programming paradigms.
>>>>
>>>> Functions in D are first-class values. It's awkward that a first-class value cannot be accessed by its identifier.
>>>
>>> I agree. But then use of functions for invocation dwarfs use of
>>> functions as first-class values, so I think requiring & for the latter
>>> is a sensible engineering decision.
>>
>>
>> By the way, D supports declarations of function type (not function pointer), though it's not documented in the spec. They always struck me as a really odd feature in C, and they're pretty confusing for newbies:
>>
>> typedef void Func(int);
>>
>> Then you get oddities
>>
>> Func * f = &foo; // OK.
>>
>> Func f = foo; // You might expect this to work, but it makes no sense.
>>
>> This is a case where you do not intuitively expect "foo" (with no &) to be a function pointer. You might as well make it a function invocation.
>>
>> It's pretty interesting to fool around with these fellas in an is() expression.
>
> Heh. That is eerily similar to the way C handles it - here's an example:
>
> // this is C
> typedef void foo(int);
>
> int main()
> {
> foo bar;
> foo baz;
> bar = baz;
> }
>
> The typedef goes through. The definitions of bar and baz go through (and are simply equivalent to an extern declaration!!!) The assignment won't go through because, bar is not an lvalue.
Is there a use case for this? I've only ever found it to be a nuisance, or a curiosity at best. It seems like a great bit of C baggage to discard.
|
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | "Andrei Alexandrescu" wrote > Steven Schveighoffer wrote: >> "Andrei Alexandrescu" wrote >>> Steven Schveighoffer wrote: >>>> "Andrei Alexandrescu" wrote >>>>> Steven Schveighoffer wrote: >>>>>> "Andrei Alexandrescu" wrote >>>>>>>> P.S. If src.next() is too lengthy, why not just adopt ++src? >>>>>>> Because people (in wake of the recently introduced array operations) may legitimately expect that to mean "increment all elements of src". >>>>>> So in one case, you believe people's assumptions aren't important, i.e. an assumption that .next without parens will not change anything on the object, yet in another case you believe people's assumptions are the main argument. This doesn't sound consistent. >>>>> Of course it is. One expectation has to do with operational consistency (albeit a tad far-fetched), the other has to do with being used to a mistaken decision in the C language design. >>>> You are assuming that the C language decision to require parentheses for all functions was a design mistake. I would argue that the design was on purpose and correctly served that purpose. The purpose was to remove ambiguity when faced with understanding code without all the context. >>> I have stated my assumption and its basis. >> >> Forgive me, but I must have missed it. I saw only your assumption (or supposition) that the C designers made a mistake. > > My post on 25 Sep 2008 17:58:52 -0500 mentions: > > "One principle that I consider universal is that a language should minimize the number of syntactic constructs that are semantically and/or pragmatically meaningless. Another that I also consider universal is that the more frequently-used constructs should be given syntactic priority over the less-used constructs, particularly when the latter are also at risk of breaking the first principle." Hidden in this statement is that you consider () to be semantically meaningless. I see it not as meaningless, but a distinction between what the symbol is supposed to represent. A property should represent a value. A function should represent an action. I'll also note that your basis/proof is not any more proof than mine ;) You just made statements about what you believe, as did I. >>> What is the basis of yours? >> >> I don't have any actual proof that they did this on purpose, I wasn't working at Bell labs when C was invented, in fact, I don't even think I was born ;) >> >> But it makes logical sense, and still does. If you want to call a function, you have to use parentheses. If you want to access the function address, no parentheses. > > This is no logic. Your proof is just stating the conclusion. It's a logical fallacy called proof by assertion. Sorry, change my statement to 'But it makes sense and still does'. And I never said it was a proof. It's a statement of my reasons behind believing the () decision was on purpose. >> It follows other design decisions they made: >> >> pointers: Access what it's pointing to, use ->, get address it's pointing to, use symbol alone. > > This is wrong too. If you use symbol alone, you are not getting its address. You are referring the pointer, which is an address. It would have been consistent with other design decisions if referring a variable alone would take its address. Not really. A function symbol by itself is the address of the function. A pointer symbol by itself is the address of the data it points to. It's the same. I don't think you understood the detail that I stated, 'get address it's pointing to', not 'get address of the pointer'. >>>> But that isn't even the questioned practice here. C designers didn't even come across the question of whether an accessor-property should imply no changes to the object, because they don't have properties. The real problem is that no matter how you define next(), you can use it in a way which makes it appear like an accessor, not a function which modifies the object. The source of the problem is D's lack of expressiveness, where I cannot define whether a function cannot be used as a property. >>> I understand your argument, but it hinges on its own definitions and assumptions. You define "accessor" and then complain that something looks like one unexpectedly. Well in some languages a.b does not change anything. In others it does. What gives? >> >> There is no hard-fast rule that an accessor cannot change things. The issue is that since any function can be an accessor you can't even try to adopt a policy in your library that says 'accessors will not change things'. Because you can't define which functions can be used as accessors and which ones can't. > > Const takes care of that. If I state that 'all accessors used in my library will not change things,' then how can I enforce this? I can't, if I ever want non-const methods that do not take arguments, because those methods could be called as properties. > >> I WANT a.b to be able to be a function call, I just want to specify which functions can be called that way, and which ones cannot, so I can define how my library behaves and someone reading code that uses it will know that my rules were followed. > > Why do you want to specify that? What difference does it make? Why would you complicate the language just for a hypothetical convention that's not even compiler-checked? It allows for (in my opinion) better coding practices that are impossible today. For one, if I restrict a member to being only accessed as a property, it is interchangable with a field later on. I think there have already been many given instances where having a defined property makes it clearer, I'm not going to repeat them all. > >>>> Even with a true property definition syntax, you cannot prevent someone from changing an object while inside an accessor, that should be defined by the constancy of the object in question. But indicating that it is preferred to use the property-style means to access the next() member function seems to be misleading to some people. >>> So that further weakens your argument. >> >> How so? I'm not talking about whether or not the compiler should restrict the developer on being able to make changes in accessors. That is what const is for. I'm talking about being able to specify a coding convention that says 'accessors shall not change things'. Currently, there's no way to prevent any function from being used as an accessor, so a library developer cannot enforce this rule to people using his library. > > I personally think it's great that any function can be used as an accessor. I'd be convinced otherwise presented a good arguments against it. What problems are you foreseeing with not being able to enforce against not using ()? I have given good arguments. You seem to dismiss them as failed proofs, but that is your call. >>>> The problem I have with your argument is how you used one case to say 'this is misleading to people, so it's not a valid solution', and in another case say 'it's only misleading because you are used to it, that doesn't matter.' The assumption of which people are important to please is the issue. I understand you can't please everyone, but you shouldn't use the 'people won't like it' argument without real evidence or proof. >>> I agree that ++array may not be easily confused with ++array[]. The situation I am trying to help is improve on a mistake in the C language design that we got so used to, we actually think it's the right thing. >> >> According to comments on this newsgroup, and some quoted bug reports, many believe that it's the D methodology of not requiring parentheses that is a mistake. As far as I can tell, it's a matter of opinion, not fact. >> >>>>>> Not that I care too much :) I am also in the camp of 'defined properties should be a language feature,' but I admit to using D-properties quite often. >>>>>> >>>>>> The two things that bug me the most about D property syntax: >>>>>> >>>>>> stuff like this: >>>>>> >>>>>> x; >>>>>> >>>>>> What the hell does this mean? It looks like it does nothing. But it could be a function call. If explicit properties were required, and x was defined as a function, not a property, then x; would be a syntax error. >>>>> And what would be the advantage? I routinely use writeln; without feeling it makes for inferior style. >>>> The advantage is not to you, it is to the reader of your code. writeln; is a complete misuse of property syntax, and IMO should not be allowed. writeln is not a property, and shouldn't be used like a property. >>> Aside from just saying it, do you have any substantive argument? >> >> The arguments have been made. As I stated, it's my opinion. >> >>>> I routinely use Tango's Stdout.newline; which I admit goes against what I am saying, but it's because I know what Stdout.newline does, and that it is a function. I would gladly change everything to Stdout.newline() if it was required. >>> To what benefit? You seem to be using it today, and that makes your own style incongruent with your argument, yet surely you'd change the style in an iffy if you thought it has serious drawbacks. >> >> The benefit is clarity. >> >> Stdout.newline; >> >> looks like a property or field of Stdout. By itself, it's somewhat jarring, but it's somewhat clear that newline is a function if you know the rules of D. > > But you do use Stdout.newline and the alleged loss in clarity doesn't seem to be phasing you. It does phase me. I sometimes catch myself doing it and add the parentheses. >> However, something like this isn't so clear: >> >> Stdout.newline.formatln("Hi there {}", var); >> >> Is newline a property of Stdout, on which I'm calling formatln, or is newline a function that I'm calling, and then using the result of that function to call formatln? Compare with: >> >> Stdout.newline().formatln("Hi there {}", var); >> >> There is no ambiguity. newline is clearly a function, not a property. > > There is no ambiguity either case. You evaluate Stdout.newline. The evaluation yields a value of some type. Then you evaluate formatln against that value. OK, then tell me what this does: x.y.z(); Is y a property/field of x or a function call with no args? I see a benefit to being able to understand a line of code without requiring lots of extra context. I have to do less lookups of the source of a function or property. > What's missing is the unstated assumption that "if it doesn't have trailing parens, it must be a field". I don't think it is useful to be making that assumption. Not in D's current state, which leaves the reader to continually look up what a symbol is until he can hammer into his brain whether a symbol is a function or not. > >> My personal habits are ones I would like to change. I'd prefer to write clearer code, not shorter code. I consider writing Stdout.newline; a bad habit fostered by the lax function calling rules of D ;) > > Giving the choice of shorter vs. clearer is a false choice, another fallacy if I remember correctly. Put another way, wouldn't you at best write shorter and clearer code? Sure, the shortest clear code I have seen is that with parentheses. There is a point at which shorter becomes less clear, in which case the choice is required. How is that a fallacy? >>>> The problem is not that you or anyone might forget that writeln is a function and not a property, the problem is when you start using the property syntax to call functions that aren't so standard, someone reading the code will be confused as to what the code is supposed to do. >>>> >>>> The advantage is, you are able to define how a symbol behaves, what the rules are for using it. It makes for clearer code. >>> I am not sure. >> >> Neither answer is definitely the 'correct' one, there are tradeoffs between both styles. I like the how D properties are so easy to write, and can be accessed like functions when needed, but I don't like how you can have weird looking code to have to decipher. Having written properties in C# quite a bit, I prefer that method of requiring a formal property definition. > > I am not seeing weird code that is there to be deciphered. There is this "writeln = 3" weirdness that I'd love to weed out, but all this required trailing parens stuff simply doesn't have any good argument working in its favor. I think we're all in agreement about writeln = 3. If this is the only thing that gets fixed, it would be a huge step. I'd prefer full properties, but this at least makes things much clearer. 'simply doesn't have any good argument' is your opinion, not a fact. -Steve |
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sergey Gromov | Sergey Gromov wrote:
> Mon, 29 Sep 2008 12:23:58 -0500,
> Andrei Alexandrescu wrote:
>> Sergey Gromov wrote:
>>> D has a simple rule for property methods. This rule has side effects. If the side effects are so bad that a hack is required to counter them,
>>> then the rule should be replaced with a better one. Otherwise your hack will inevitably introduce new, less obvious side effects than those it were supposed to fight, and will finally require other hacks.
>>>
>>> struct Range
>>> {
>>> ref int head() {...}
>>> }
>>> Range r;
>>> r.head = 5; // error
>> A function can return an object that allows assignment even today with opAssign.
>
> Today the compiler tries to call Range.head with one argument and fails. Another side effect needs hacking.
Well I'd rather say, an awkwardness that needs fixing.
Andrei
|
September 29, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tue, Sep 30, 2008 at 3:36 AM, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>> There is no ambiguity either case. You evaluate Stdout.newline. The evaluation yields a value of some type. Then you evaluate formatln against that value.
>
> OK, then tell me what this does:
>
> x.y.z();
>
> Is y a property/field of x or a function call with no args? I see a benefit to being able to understand a line of code without requiring lots of extra context. I have to do less lookups of the source of a function or property.
The problem with this argument is that unless you disallow properties altogether, you still won't know whether y is actually a field or a call to a property method without looking it up.
--bb
|
Copyright © 1999-2021 by the D Language Foundation