October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michel Fortin | Michel Fortin wrote:
> Without aggreement on a formal definition for properties and compiler enforcability, I find it very difficult to justify a formal syntax for properties.
I agree. Moreover, there should be arguments on why the distinction useful. I liked it from day 1 that D made properties just a particular case of functions, and I'd love to keep it that way. It would obviate discussions such the one mentioned about C#.
Andrei
|
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote: > Bill Baxter wrote: >> On Tue, Sep 30, 2008 at 4:08 AM, KennyTM~ <kennytm@gmail.com> 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 think the counter-argument to what I just said is that if properties >> had to be declared explicitly then at least we would know that .y is >> either a field or else something the designer *intended* to behave >> like a property. Which does tell us something. It most likely means >> that it's not an extremely heavy-weight operation, just a lightweight >> accessor with maybe a little logic on top. That could be wrong, but >> in that case it's the class designer's fault for misleading us. > > So the logic is: > > "A field can be accessed with a.b, but not with a.b(). Therefore if someone writes a.b, it may be a field or code, but it someone writes a.b() it will always be code. Given that a field is cheap and code ranges from cheap to expensive, good style is to have a.b always refer to cheap stuff, and a.b() always refer to not-expected-to-be-cheap stuff." > > I agree with that logic. It makes for a nice convention. (That convention is already broken by the built-in dup and sort, but let past mistakes be past mistakes.) My response to that is that concerns of keeping the language simple and of facilitating generic code are counterarguments that should be weighed in as well. > In what way does that convention/style go against facilitating generic code? > An experience anecdote - when I wrote Loki I went for the convention that if a type template argument only accepts built-in types it should be written "class T", otherwise it should be written "typename T". The convention was a failure: lack of compiler enforcement meant that "bugs" would be in there without being noticed (and readers would subsequently complain about inconsistencies), at times it was even unclear whether a template would accept certain built-in types or not and there was no way to check that, etc. A similar fate could happen for that convention. It could be nice, yes, but it could also become a nuisance ("was I expected to put parens here, or not? Hell, nobody seems to care anyway, at least this version of the library."). > Uh, of course, and that's why we want this convention to be enforced by the language, and not be merely a convention. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote: > > I routinely use writeln; without feeling it makes for inferior style. > Dear Gods! O_o -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote: > Andrei Alexandrescu wrote: >> Benji Smith wrote: >>> 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. >> >> Consistency is good, but that's not consistency. >> >> http://www.merriam-webster.com/dictionary/consistency >> >> agreement or harmony of parts or features to one another or a whole : >> correspondence ; specifically : ability to be asserted together without >> contradiction >> > > The concept of "consistency" has a more specialized meaning when applied to language design. (just has it has in other fields, like mathematics) > So I agree with benji that not having "The expression of a semantic construct should always use the same syntax" is not being consistent. (There are of course other situations where things can be inconsistent.) No. Not at all. For consistency you must assert together something with something else. If there are two possible and equivalent syntaxes for a feature that's not lack of consistency. It's waste. We'd be talking about consistency if at most "syntax in context A should be the same as syntax in context B". But if the context is irrelevant to the syntax then we're not quite talking about consistency. Let me give another example. One could say in C++ overloading template functions is inconsistent with overloading regular functions because they follow very different rules. The fact that in C++ you can specify either "class" or "typename" for a template parameter is NOT inconsistent. It is wasteful. > If you don't agree with this definition of "consistency", I'm not gonna argue with that , just substitute it with "conzistency" or "foobar", or whatever and proceed. No. Defining terms is important. If we have the wrong terms in mind when talking about something, communication is impeded. >> An example of consistency is that user-defined operators have the same >> syntax and precedence as built-in operators. >> >>> Based on that principle, I'd argue that function-calling should either always use parentheses, or it should never use parentheses. >> >> Yah I'd like that too. It's economy of syntax. >> > > Then why are you not suggesting, or campaigning for, such change? Because language design is putting many desiderata in agreement, not following one blindly. >>> Requiring parentheses for some function calls, but not for others violates the principle of consistency. >> >> No. It violates economy of syntax. There are many syntaxes for the same >> semantics. > > It violates consistency, as defined above. No. You can't define a term to mean whatever you want. I mean you can, but then it's hard to communicate. > It may violate economy of syntax as well (or it may be the same thing). Whatever. What I ask is, what would you suggest to fix it? Should all function calling not use parenthesis? And how would that syntax be? I'm happy with how things are now except for the assignment that is accepted all to often. I suggested a simple fix for that. Andrei |
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Don | Don wrote: > 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. What exactly are you trying to discard? Just the typedef void foo(int); syntax? Or any typedef of a function type? Like void func(int); typedef typeof(func) foo; ? -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote: > Sergey's argument (which is much more objective than subjective) is not strictly against omitting parenthesis, but rather against ambiguity (the dual possible ways to call zero-args functions), which as has been shown, creates various possibilities for bugs when you mix functions that return delegates. This ambiguity problem would also be resolved if omitting parenthesis would be *the only way* of calling functions with zero-args. Yah, he made great points. There are ambiguities. The counter-argument is that that would make the syntax of calling functions with no arguments inconsistent with the syntax of calling function with arguments. The "()" is a degenerate case of "(a, b, c)". So it's hard to keep everybody happy. > Anyways, I also agree with principles 1 and 2. But I also agree with some other principles that sometimes conflict with those first ones (which is what is happening here). And in each such scenario I would have to weight in to see which principle I would give priority. Yes, there are other principles to follow too. And somehow they often participate in a weighted average in many design decisions. > These other principles are: > > 3 - Consistency of syntax - The same language feature should use the same syntax, with as little variations as possible. > > This principle fails here because when you have functions with parameters you have to use parenthesis, and only when you don't have arguments you omit the parenthesis. But the zero-args case should not be different from the n-args case. Of course, this could be solved by having a syntax for the n-args case that also doesn't use parenthesis (see my OP after Benji's thread) Great. Yes, that is consistency. I swear that all I wrote above was before I saw this :o). > But most importantly: > 4 - Common ground with other programming languages. There are several things that are common with many, if not all, of the mainstream programming languages (Java, C#, C/C++, Ruby, Python, etc.). > One of them is using parenthesis for calling functions! (See KennyTM's post with the table describing function calling for several languages.) Using parenthesis comes from math. And of that list, only VB 6, Pascal and Perl, have the possibility of omitting parenthesis. And frankly, VB6 and Pascal don't matter since they are pretty much obsolete. And Perl is language with a hack-ish nature, IMO. Even Lisp uses parenthesis for function calling! (even if in a different position, and even if it's pretty much the only syntax it has). > This is a subjective principle, I can't tell you to want to like having common ground with other languages, but c'mon... "writeln;"? Seriously?? That's just hideous. I agree that 4 is a good principle. I'd even call it "consistency" - across languages that is. But let's not forget that C# defined an entire feature - properties - to fulfill what was perceived as a need. Also the Cecil language goes as far as requiring accessors for any field (and defining methods implicitly when missing). Eiffel also has properties that are obtained via syntactic conventions (getX and setX implement property x). People want to add properties to Java 7 (unfortunately the google search is clogged by a Java class called Properties so it needs some combing). I use writeln; all over the place, and more importantly obj.method, without finding them hideous. I'm impressed a lot by the analogy with math because it is one extra argument in my favor. In math there's no function without arguments. At most people would say f(.) (with a central dot) when referring to what is akin to the address of the function. Andrei |
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote:
> Andrei Alexandrescu wrote:
>>
>> I routinely use writeln; without feeling it makes for inferior style.
>>
>
> Dear Gods! O_o
What are you gonna do? People are different. If the best you can say against it is that it's "hideous", we should visit a modern art gallery :o).
Andrei
|
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote:
> Andrei Alexandrescu wrote:
>> Bill Baxter wrote:
>>> On Tue, Sep 30, 2008 at 4:08 AM, KennyTM~ <kennytm@gmail.com> 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 think the counter-argument to what I just said is that if properties
>>> had to be declared explicitly then at least we would know that .y is
>>> either a field or else something the designer *intended* to behave
>>> like a property. Which does tell us something. It most likely means
>>> that it's not an extremely heavy-weight operation, just a lightweight
>>> accessor with maybe a little logic on top. That could be wrong, but
>>> in that case it's the class designer's fault for misleading us.
>>
>> So the logic is:
>>
>> "A field can be accessed with a.b, but not with a.b(). Therefore if someone writes a.b, it may be a field or code, but it someone writes a.b() it will always be code. Given that a field is cheap and code ranges from cheap to expensive, good style is to have a.b always refer to cheap stuff, and a.b() always refer to not-expected-to-be-cheap stuff."
>>
>> I agree with that logic. It makes for a nice convention. (That convention is already broken by the built-in dup and sort, but let past mistakes be past mistakes.) My response to that is that concerns of keeping the language simple and of facilitating generic code are counterarguments that should be weighed in as well.
>>
>
> In what way does that convention/style go against facilitating generic code?
A generic function writing obj.symbol cannot work across objects that implement symbol as a computed property vs. a field.
Andrei
|
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote:
> On Thu, Oct 2, 2008 at 8:26 PM, Michel Fortin <michel.fortin@michelf.com> wrote:
>> Compare this with properties which have exactly the same performance,
>> memory, and flexibility implications as regular functions. The only
>> difference between a property and a function is the meaning the author give
>> to it, and that meaning vary between authors and contexts. Which means that
>> from the API user point of view, something being a property or a function
>> doesn't mean much... except of course that the user has to remember if
>> Singleton.Instance is a property or a function before using it, or else
>> suffer some useless compiler errors.
>
> Good points.
>
> I think this discussion is diverging a little far from the real raison
> d'etre for property syntax, though. They are there in the first place
> not to save the typing of a few () here and there, but to allow a
> library designer to start with a plain field when that suffices and
> transition to a function later if that becomes necessary, without
> breaking client code. And there's where we can invoke a grand
> principle of software design as Andrei would have us do:
>
> * Changing implementation details should not affect client code.
>
> Ok I guess that's a software design principle, not language design but
> I guess I can say the underlying language principle is that the a good
> language should facilitate good software design.
>
> This one has to trump principles about economy of syntax and such,
> because the point of having a language in the first place is to make
> writing software easier/better/faster.
>
> More specifically this is a case of where we want syntax to facilitate
> making the transition from a simple field to something with some logic
> too. So what can we hope to get from the language to support this in
> the best way possible. These two conclusions seem pretty obvious to
> me:
>
> 1) The "fake" field's behavior should be indistinguishable from real
> field behavior in as many circumstances as possible. This prevents
> client code from having to change. This is why things like += on a
> property should be transformed by the compiler.
> 2) In situations where behavior does differ from that of a real field,
> a compiler error should occur at the point of usage. This prevents
> nasty surprises where code silently starts behaving incorrectly. This
> suggests that something like attempting to take the address of the
> field should be a syntax error if the field is turned into a property
> function. (This probably already happens in most cases since a
> function pointer won't usually be interchangeable with an int pointer
> or whatever it was before)
>
> Anyway, the point I want to make is that while it's neat that you can
> save typing a few parentheses, there are more important things, like
> being able to refactor code locally and knowing with reasonable
> certainty that all client code will either still work correctly or
> fail to compile.
>
> Going by these principles could lead to some interesting conclusions
> like for instance an argument that you shouldn't be able to take the
> address of a property function, or do anything else to it that exposes
> the fact that it is not, in fact, a field.
Yes, I entirely agree. I mentioned this a couple of times, but never explained it so well and thoroughly.
Andrei
|
October 02, 2008 Re: Revised RFC on range design for D2 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bill Baxter | Bill Baxter wrote: > > --- > Somewhat unrelated, but there still exists the annoyance in D that if > you have to functions with the same name and you want to take the > address of one of them, you can't. Furthermore I can't think of a > reasonable syntax to do that easily. For that reason, I really think > the best getter and setter functionality in D would be something where > you have distinctly named *functions* getProp and setProp for when you > want/need functions mirroring samely-named *properties* for which only > property syntax would work. > Hum, that reminds me of an idea I once had for properties: not using a keyword, but only convention, just as the op* methods for operator overload. Basicly one writes a property with getter and setter functions, like Java: class Foo { SomeBar getSomeBar(); void setSomeBar(SomeBar someBar); } one can then access those functions normally, like Java, but one would then also be able to use a property with the same name of the getter/setter methods, but without 'get' or 'set', and with the capitalization of the first letter fixed, like this: Foo foo = ...; SomeBar someBar = foo.someBar; //same as: SomeBar someBar = foo.getSomeBar(); foo.someBar = new SomeBar(); //same as: foo.setBar(new SomeBar()); This makes it easy to use Java-style code (for instance when porting Java code, or using libs like DWT, etc.). What I don't like here, is that this solution involves working with the capitalization/CamelCase of the property, which doesn't sound right. And what about properties that start with a capital letter?... :( -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
Copyright © 1999-2021 by the D Language Foundation