September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jason House | Jason House wrote: > KennyTM~ Wrote: > >> Bill Baxter wrote: >>> 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 >> I think the distinction of with and without () is pretty stylistic, because the same argument can even be applied to operator overloading (does a=b means pointing the variable a to b, or calling a.opAssign(b)?) >> >> For me, I would use () if the function do modify the object itself. >> > > I assume you'd also want parens if the function modified global state? If so, I believe you'd want parens with all impure member function calls. Right. Therefore if I were to implement property getters I would require it as an immutable (or at least const) method itself. I don't know what's the use of global functions that is pure AND does not take any input. > Obviously, we're talking about property getters and not setters. I was told once already that such things are off topic :) I think it's relevant to the spirit of the conversation. |
September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | "Michel Fortin" wrote > On 2008-09-29 12:55:18 -0400, "Steven Schveighoffer" said: > >> 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. > > Interesting. To me both of these things have exactly the same meaning. Perhaps it's because I'm used to D, but I think it's more because I can't count how many times I've seen this pattern in C++: > > SomeSimgleton::Instance().doSomething(); > > where Instance() is simply an accessor. Yes, that is a workaround for not having property constructs available. The intuitive label of 'property' comes from the name of the getter 'Instance'. It screams that you are getting the instance of the class, and it's well accepted as a property. What has happened is that instead of relying on the compiler to enforce what is a property and what is not, you are relying on the interpretation of English words. But in a language like C#, you would define Instance as a property, not a function. So it would never look like that. In D, properties are equivalent to functions, so you have a choice as to whether to use the parentheses or not. But that isn't the problem, the problem is really that you can call functions as properties. > In my opinion, "newline" isn't a good function name for what it does because it has no verb. Having no verb makes it look like an accessor much more than the absence or presence of parenthesis. So newline() seems like a property to you more than 'start a new line'? I suppose I can see that, but consider if you were used to a system where properties *prohibited* parentheses, and functions *required* them. It becomes less about interpretation of English vocabulary and more about compiler-enforced interface. I like that system better. -Steve |
September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | "Andrei Alexandrescu" wrote
> Andrei Alexandrescu wrote:
>> How about this. Maybe if we attacked this annoyance in particular, that would be a large bang for the buck without a landslide change in the compiler. We only need some way to inform the compiler, "yes, it's ok to call a.b(c) as a.b = c". Ideas?
>
> I actually did have something in mind when I wrote this, just didn't want to bias anyone.
>
> My thinking is that the syntax "a.b = c" in lieu of a.b(c) for a function a.b(T x) should be allowed if and only if there also exists a function a.b() that returns a value of type T.
What about functions with default parameters?
struct S1
{
int prop(int x = 0) {...}
}
I admit I have no idea how this should be interpreted. The author may have intended for this to compile:
s1.prop = 5;
-Steve
|
September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to KennyTM~ | KennyTM~ Wrote: > Jason House wrote: > > KennyTM~ Wrote: > > > >> Bill Baxter wrote: > >>> 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 > >> I think the distinction of with and without () is pretty stylistic, because the same argument can even be applied to operator overloading (does a=b means pointing the variable a to b, or calling a.opAssign(b)?) > >> > >> For me, I would use () if the function do modify the object itself. > >> > > > > I assume you'd also want parens if the function modified global state? If so, I believe you'd want parens with all impure member function calls. > > Right. Therefore if I were to implement property getters I would require it as an immutable (or at least const) method itself. Const and immutable functions can modify global state... So I don't think you'd want that. PS: D's const functions don't guarantee they won't modify the object. > I don't know what's the use of global functions that is pure AND does not take any input. > > > Obviously, we're talking about property getters and not setters. I was told once already that such things are off topic :) I think it's relevant to the spirit of the conversation. |
September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | Michel Fortin wrote: > On 2008-09-29 23:12:44 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said: > >> Indeed, whether or not something can be used as a property will depend on the qualifiers in vigor. > > And I think this is why binding the availability of the proprety syntax of the setter to the existance and visibility of a getter is not a good idea. > > Basically, doing this makes the "()" syntax safer, and the "=" version more fragile, as the later could become non-functionnal in all kinds of situations where the getter becomes unavailable (removal, deprecation, change in protection, change in constness of the parent, etc.). It means that if I remove or change the visibility of a getter in a program (because it has been found to be erroneous, dangerous, and/or badly used), I will have to change all the calls to the corresponding setter to use the parenthesis form. > > This can be a nuisance while refactoring. It also means that I can't just remove the getter and attempt to recompile to check if it's called somewhere without inducing compilation errors where the setter is used. And I'm sure it'll encourage some silly ones who want to write write-only properties to add a dummy getter that throws an exception, disregarding static checking. I can already see some people recommanding always using the parenthesis syntax when calling setters because then you know you won't have to change it later when you refactor your code; I know I would consider it if I got biten by this, after all we're already doing this in other languages and it's not that painfull. I think the argument is overstated and a corner case is overblown, but I agree there is an issue. > So I think this idea brings unnecessary coupling between functions, with more drawbacks than benefits. Don't mistake me, I liked your idea at first, especially because I'm not fond of adding a new syntax just for diallowing another, but now I realise don't like its implications of the implicit coupling of the setter with the getter. > > I believe explicit coupling would be better, and that probably means an explicit property syntax as others have requested. But then again, I don't mind much if things stay like they are. > > - - - > > Another funny example: > > module a; > void func(int a); > > module b; > int func(); > > module c; > import a; > import b; > void main() > { > func(func); // compiles... so > func = 5; // compiles too! > } > The coupling part I agree with, it's unfortunate. Well I guess I'll just drop the matter. Andrei |
September 30, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jason House | Jason House wrote: > > > Const and immutable functions can modify global state... So I don't think you'd want that. > Does "pure" in an object method takes the object itself as input also? If so, then I mean the parenthesis can be omitted if the method is pure. If not, then it has no solution in current D. The problem is I see no official examples in pure object methods. So far I can only find mentioning of pure global functions, or I've overlooked. > > PS: D's const functions don't guarantee they won't modify the object. > I still can't quite grasp the invariant-madness in D :p Practically I have only used the "in" storage class in parameter list*, invariant methods and .idup for some string-related manipulations. P.S. *: "in" was "invariant scope". When did it changed to "const scope"?? > > > >> I don't know what's the use of global functions that is pure AND does not take any input. >> >>> Obviously, we're talking about property getters and not setters. I was told once already that such things are off topic :) I think it's relevant to the spirit of the conversation. > |
October 01, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote:
> 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
One thing that I've found especially annoying about the current implementation is this:
x.y = 3; // Working code
x.y += 3; // Broken, if x.y is actually a function
x.y = x.y + 3; // Ugly work-around
I've been bitten by this at least a dozen different times. Having a real property syntax would eliminate cases like that.
--benji
|
October 01, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> I stated two principles of language design. They could be true or false. They are up there for debate. They are subjective, because aside from some basics, language design is subjective.
>
> The principles are:
>
> 1) A language should minimize the number of syntactic constructs that are semantically and/or pragmatically meaningless.
>
> 2) 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.
I'd like to propose another principle of language design:
3) Consistency -- The expression of a semantic construct should always use the same syntax. Likewise, multiple uses of the same syntactic constructs should always result in the same semantics.
Based on that principle, I'd argue that function-calling should either always use parentheses, or it should never use parentheses.
Requiring parentheses for some function calls, but not for others violates the principle of consistency.
In my prioritization of language-design principles, consistency is more important then syntactic economy.
Based on those principles, I believe that the parentheses should be mandatory for all function calls.
--benji
|
October 01, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benji Smith | On Wed, 01 Oct 2008 07:58:20 +0200, Benji Smith <dlanguage@benjismith.net> wrote: > Bill Baxter wrote: >> 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 > > One thing that I've found especially annoying about the current implementation is this: > > x.y = 3; // Working code > x.y += 3; // Broken, if x.y is actually a function > x.y = x.y + 3; // Ugly work-around > > I've been bitten by this at least a dozen different times. Having a real property syntax would eliminate cases like that. > > --benji It seems we will soon get reference return values, in which case this would no longer be a problem. I have also written a property template that enables things such as that, but it would also benefit immensely from reference return values. -- Simen |
October 01, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjaeraas | Simen Kjaeraas wrote:
> On Wed, 01 Oct 2008 07:58:20 +0200, Benji Smith <dlanguage@benjismith.net> wrote:
>
>> Bill Baxter wrote:
>>> 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
>>
>> One thing that I've found especially annoying about the current implementation is this:
>>
>> x.y = 3; // Working code
>> x.y += 3; // Broken, if x.y is actually a function
>> x.y = x.y + 3; // Ugly work-around
>>
>> I've been bitten by this at least a dozen different times. Having a real property syntax would eliminate cases like that.
>>
>> --benji
>
> It seems we will soon get reference return values, in which case this would
> no longer be a problem. I have also written a property template that enables
> things such as that, but it would also benefit immensely from reference
> return values.
>
It's still an issue if we want to support property setters, say
class Time {
private double seconds;
invariant /*pure?*/ double minutes () { return seconds/60.; }
void minutes (invariant double x) { seconds = x*60.; }
}
You cannot return a double& when calling .minutes because it simply does not exist. Therefore, the interpreter have to clever enough to convert
t.minutes += 2;
into
t.minutes = t.minutes + 2;
i.e.
t.minutes(t.minutes() + 2);
if .minutes does not return a reference. A similar problem also exist with .opIndexAssign and .opSliceAssign.
|
Copyright © 1999-2021 by the D Language Foundation