April 24, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On 24 apr 2011, at 01:27, Jonathan M Davis wrote: >> On 22 apr 2011, at 00:28, Jonathan M Davis wrote: >>> Actually, setters _should_ return void. The chaining should be done by calling both the getter and setter functions. The other options is a property function which takes nothing but returns a ref. In either case, the chaining would work. >> >> Wouldn't this require some form of property rewriting? > > Hmmm. Yes it would, which I was thinking was what properties were doing anyway, but now that I think on it, I'm not sure they do. The getter certainly doesn't, but I don't know about the setter. So, I'm not quite sure what the compiler is doing right now, but calling both the getter and setter for chained assignment would require a lowering. I'm pretty sure it doesn't do any property rewriting. There's also this problem (that also C# has) that also has been discussed before: foo.bar.value = 3; "foo" is a struct or an object. "bar" is a getter property which returns an object and "value" is setter property that sets a value. If you have some kind validation in a "bar" setter property it will be bypassed. This can be fixed with property rewriting. BTW, I pretty sure there's an issue in bugzilla about this. > Then again, now that I think of it, if you require both the getter and setter for chained assignment, chained assignment won't work for write-only properties. So, I don't know what the solution should be. It was my understanding that a function could _be_ a setter if it returned anything. It had to take a single value and return nothing (or take two values where the first was an array and you were calling it using the array's member function call syntax). And with that being the case, you _must_ use the getter to generate chained assignments. Can't that be a requirement, to have a getter, to be able to do chained assignment. How often do you actually provide only a setter without a getter? > So, now I'm a bit confused on the chained assignment bit. The fact that the compiler virtually ignores @property right now makes it much harder to determine how it's supposed to work. It was my understanding that > > T prop() //getter > void prop(T val) //setter > ref T prop() //both getter and setter > > were supposed to be the only valid signatures for getters and setters (save for the addition of the array parameter with arrays), and it seems like that's not currently true. TDPL is very specific that the syntax is supposed to be strictly enforced, but it's not very specific on the correct signatures for getters and setters. I always return the set value in a setter to allow chained assignments. > So, after this discussion, I'm at least marginally confused. Certainly, a lot of what some folks expect of properties comes from what currently works rather than what's supposed to work, and what's supposed to work is not always clear - at least as far as the exact signatures for getters and setters go. Yeah, with D that seems to happen far to often. The compiler does one thing, the specification says another thing and now with the addition to TDPL we possibly have a third interpretation. > - Jonathan M Davis > _______________________________________________ > phobos mailing list > phobos at puremagic.com > http://lists.puremagic.com/mailman/listinfo/phobos -- /Jacob Carlborg |
April 24, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | On 23 apr 2011, at 23:20, Robert Jacques wrote: > On Sat, 23 Apr 2011 16:06:35 -0400, Jacob Carlborg <doob at me.com> wrote: > >> >> On 23 apr 2011, at 17:32, David Simcha wrote: >> >>> On 4/23/2011 11:24 AM, Jacob Carlborg wrote: >>>> I think I would like to have something in the middle of strict and loose semantics. I would like that functions marked with @property have to be called like a field: >>>> >>>> auto bar = foo.field; >>>> foo.field = 3; >>>> >>>> But functions not marked with @property still can be called without the parentheses: >>>> >>>> foo.bar(); >>>> foo.bar; >>> >>> Maybe there's been some misunderstanding, but actually this is what loose semantics means. Loose semantics (at least as I understand them) mean stuff marked @property would not be callable using method syntax, and this rule would be used to disambiguate the corner cases, but nothing would change for stuff not marked @property. >> >> Ok, then I probably misunderstood. What about: >> >> writeln = "foo"; >> >> is that already fixed? > > If by fixed, you mean doesn't compile, then yes, it's fixed. But this might be a quality of implementation issue, regarding method syntax and templates and not a true theoretical fix. Case in point: printf = "foo" works. However, while ugly, neither writeln = "foo" nor printf = "foo" are doing something the original author didn't intend. The greater violators (which actually caused bug reports/confusion) are those where the statements became nonsense, like math_function = 5 or obj.factory_method = 6.[1] Fixes for most of these issues exist: Not using the result from a strongly pure function should be an error, not matter how it's called. And const/immutable methods shouldn't be assignable, since you can't assign to a const or immutable variable. Static/free functions can't be marked const/immutable, but considering the only thing they can modify is global state, pure is equivalent. So neither strongly nor weakly pure functions should be assignable. If writeln = "foo"; doesn't compile but printf = "foo"; does then I would consider it not fixed. The way I would want @property to behave is disallow bar = "foo"; for functions not marked with @property. But still allow functions not marked with @property to be callable without parentheses. > From a theoretical perspective, assignment is a function which stores a value (in addition to taking an input and producing an output, like any other function). Since we can cleanly express in D whether a function modifies external state (i.e. stores values) via pure/const/immutable, we can detect and error on non-consistent uses of assignment. This won't be perfect, because not all functions which modify state store something from a high-level point of view, but it covers a lot (all?) of the common use cases. > > Regarding your question, writeln/printf = "foo" would still be valid under these new tests; but to play devil's advocate, maybe you do kernel development work, etc, and mentally model I/O as writing to specific memory locations. That mental model actually prefers printf = "foo" to printf("foo"). > > P.S. I've never liked the writeln = "foo" example, because it's of the form verb = value, and therefore feels like a straw men. The more realistic situation is noun = value, but its very hard to find this kind of example that is A) named in a way such that a user might reasonably make an assignment to it and B) also feels natural as a method call. > > [1] In the actual examples, the use of a noun for the factory function name lead to the confusion. > _______________________________________________ > phobos mailing list > phobos at puremagic.com > http://lists.puremagic.com/mailman/listinfo/phobos -- /Jacob Carlborg |
April 24, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Sun, 24 Apr 2011 07:29:22 -0400, Jacob Carlborg <doob at me.com> wrote: > On 24 apr 2011, at 01:27, Jonathan M Davis wrote: > >>> On 22 apr 2011, at 00:28, Jonathan M Davis wrote: >>>> Actually, setters _should_ return void. The chaining should be done by >>>> calling both the getter and setter functions. The other options is a >>>> property function which takes nothing but returns a ref. In either >>>> case, >>>> the chaining would work. >>> >>> Wouldn't this require some form of property rewriting? >> >> Hmmm. Yes it would, which I was thinking was what properties were doing >> anyway, but now that I think on it, I'm not sure they do. The getter >> certainly >> doesn't, but I don't know about the setter. So, I'm not quite sure what >> the >> compiler is doing right now, but calling both the getter and setter for >> chained assignment would require a lowering. > > I'm pretty sure it doesn't do any property rewriting. There's also this problem (that also C# has) that also has been discussed before: > > foo.bar.value = 3; > > "foo" is a struct or an object. "bar" is a getter property which returns an object and "value" is setter property that sets a value. If you have some kind validation in a "bar" setter property it will be bypassed. This can be fixed with property rewriting. BTW, I pretty sure there's an issue in bugzilla about this. Yes, there is a a bug about it, but it doesn't occur when 'bar' is an object/ref T, it occurs when 'bar' is a struct/value type. It happens because 'a.b.c = 5' gets rewritten into 'auto temp = a.b; temp.c = 5;' If b/temp is a reference type, then that store is meaningful. However, if b/temp is a struct/value type, then assignment is made to a local copy and is lost. I believe the proposed fix would is: 'a.b.c = 5' => 'auto t = a.b; t.c = 5; a.b = t;', with greater number of temporaries as the number of references lengthens. >> Then again, now that I think of it, if you require both the getter and >> setter >> for chained assignment, chained assignment won't work for write-only >> properties. So, I don't know what the solution should be. It was my >> understanding that a function could _be_ a setter if it returned >> anything. It >> had to take a single value and return nothing (or take two values where >> the >> first was an array and you were calling it using the array's member >> function >> call syntax). And with that being the case, you _must_ use the getter to >> generate chained assignments. > > Can't that be a requirement, to have a getter, to be able to do chained assignment. How often do you actually provide only a setter without a getter? I've written and used setters that don't have a getter before, but they are not a common use case. But I don't believe you could have such a method be anything other than the last one in the chain. i.e. given 'a.b.c = 5', c doesn't need to have a getter, but b definitely does. (Also, 'a.b.c += 5' would require c to have a getter) |
April 24, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Sun, 24 Apr 2011 07:33:30 -0400, Jacob Carlborg <doob at me.com> wrote:
> On 23 apr 2011, at 23:20, Robert Jacques wrote:
>> On Sat, 23 Apr 2011 16:06:35 -0400, Jacob Carlborg <doob at me.com> wrote:
>>> On 23 apr 2011, at 17:32, David Simcha wrote:
>>>> On 4/23/2011 11:24 AM, Jacob Carlborg wrote:
>>>>> I think I would like to have something in the middle of strict and loose semantics. I would like that functions marked with @property have to be called like a field:
>>>>>
>>>>> auto bar = foo.field;
>>>>> foo.field = 3;
>>>>>
>>>>> But functions not marked with @property still can be called without the parentheses:
>>>>>
>>>>> foo.bar();
>>>>> foo.bar;
>>>>
>>>> Maybe there's been some misunderstanding, but actually this is what loose semantics means. Loose semantics (at least as I understand them) mean stuff marked @property would not be callable using method syntax, and this rule would be used to disambiguate the corner cases, but nothing would change for stuff not marked @property.
>>>
>>> Ok, then I probably misunderstood. What about:
>>>
>>> writeln = "foo";
>>>
>>> is that already fixed?
>>
>> If by fixed, you mean doesn't compile, then yes, it's fixed. But this might be a quality of implementation issue, regarding method syntax and templates and not a true theoretical fix. Case in point: printf = "foo" works. However, while ugly, neither writeln = "foo" nor printf = "foo" are doing something the original author didn't intend. The greater violators (which actually caused bug reports/confusion) are those where the statements became nonsense, like math_function = 5 or obj.factory_method = 6.[1] Fixes for most of these issues exist: Not using the result from a strongly pure function should be an error, not matter how it's called. And const/immutable methods shouldn't be assignable, since you can't assign to a const or immutable variable. Static/free functions can't be marked const/immutable, but considering the only thing they can modify is global state, pure is equivalent. So neither strongly nor weakly pure functions should be assignable.
>
> If writeln = "foo"; doesn't compile but printf = "foo"; does then I would consider it not fixed. The way I would want @property to behave is disallow bar = "foo"; for functions not marked with @property. But still allow functions not marked with @property to be callable without parentheses.
I have not heard this particular combination before; thank you. More choices are always appreciated. There are real, practical use cases for not- at property methods with write-only field semantics, which this would prevent. And between a real use case and a synthetic straw-man, I believe the use case should win. However, I am interested in any of the practical issues which inspired writeln = "foo", if you know of any.
Also, this and another post have given me an idea: what if non- at property methods could be assigned to if and only if a valid 'getter' also existed. This would still 'fix' writeln = "foo" but be a less restrictive than an outright ban.
|
April 25, 2011 [phobos] Fw: Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | Sorry, I keep forgetting to change the reply to address to phobos.
grrrrr....
-Steve
----- Forwarded Message -----
> From: Steve Schveighoffer <schveiguy at yahoo.com>
> To: Robert Jacques <sandford at jhu.edu>
> Cc:
> Sent: Monday, April 25, 2011 7:57 AM
> Subject: Re: [phobos] Time to get ready for the next release
>
>
>
>
>> ________________________________
>> From: Robert Jacques <sandford at jhu.edu>
>> To: Steve Schveighoffer <schveiguy at yahoo.com>; Discuss the phobos
> library for D <phobos at puremagic.com>
>> Sent: Saturday, April 23, 2011 1:03 PM
>> Subject: Re: [phobos] Time to get ready for the next release
>>
>> On Fri, 22 Apr 2011 13:22:31 -0400, Steve Schveighoffer
> <schveiguy at yahoo.com> wrote:
>>>> From: Robert Jacques <sandford at jhu.edu>
>> [snip]
>>>> Third, came criticisms of naming a factory method 'seconds'
> in the first place (noun/verb distinctions, etc), and the associative criticisms of fixing a bad design via a proverbial sledgehammer.
>>>
>>> The goal was to have something short.? At the time, I was fighting for
> changing the time code in Tango, and one of the criticisms was that the factory method names were too long (don't remember what I originally had).? Code like Socket.select(5.0) was going to be replaced with Socket.select(TimeSpan.seconds(5)).? This was sort of a compromise.? Ironically, we had to change it to something more verbose because of this problem.
>>
>> I understand. But I think you side-stepped my actually thought a bit, so let
> me be a bit more verbose. Conciseness and clarity are probably the two most at
> odds aspects of any API design. The general conventions are
> variables/fields/'property's should be names and functions/methods
> should be verbs. I have seen many a post in the 'property' discussions
> regarding how verb = value or noun(value) is Evil(TM). Personally, I take it as
> a rule of thumb and not as a hard and fast rule. Anyways, any designer who uses
> a noun for an action, should be aware that they are actively courting the very
> confusion in this bug report. So, from an API design perspective, the author
> sacrificed too much clarity for consciousness. And this criticism remains true
> even with @property, enabled. Users are still going to try compile s.seconds =
> 5, because the API design of 'seconds' differs from the design of its
> class, its module, its library and general expectations. They are
> just going to get a compiler error, instead of a do nothing expression. And
> while we deal with non-standard designs all the time, in the form of DSLs,
> mini-DSLs and 'by convention' frameworks, a single, non-standard
> function generally only increases a programmer's cognitive load, without any
> additional benefits. And proposing the creation/justification of a language
> level features in order to mitigate (not fix) a minor issue with an API, which
> exists solely due to the API's poor design (which violates its class's
> design guides), is like taking a sledge hammer to kill a fly.
>
> I agree with all of this, actually.? I don't love the interface, but it was a compromise, and as far as intuitiveness goes, it's pretty low on the scale.? However, you have to pick your battles, and having a much better time API in tango was better than having the code refused over somewhat bikeshed issues.
>
>
> I think this was half a victim of D's flawed property design, and half a victim of being able to call static functions using an instance for namespace.? Fix the latter problem in the compiler, and the function can only be called with the struct name as the namespace.? However, it does not remove the property issue:
>
> TimeSpan.seconds(5); // looks ok to me, not great, but not misleading either.? It looks like a constructor, which it actually is.
>
>
> TimeSpan.seconds = 5; // absolutely misleading.
>
> So I think even though it's somewhat of a combination of issues, the property issue is not invalid.
>
> The issue is more prevalent when talking about ambiguous words, especially ones that can be both nouns/adjectives and verbs.? The issue I have with not being able to require parentheses is, lack of parentheses evoke an expectation of a field, either setting or getting that field.? Parentheses evoke more of an action than a field, but that's not as strong, because you can easily make a function that is a property.
>
> If you just require @properties to be called without parentheses, it doesn't solve the largest problem with D's property system -- that is, being able to omit parentheses for things that should clearly be viewed as actions.
>
> Here is an artificial, but not so improbable example:
>
> stream.read = buf;
>
> what does this mean?? Does it mean, set the read buffer to buf?? Does it mean read buf into the stream?? I have no idea.? But this is completely clear:
>
> stream.read(buf);
>
> it means, read the stream data into buf.
>
> However, D treats them both equivalently, and throws no error on the super-confusing usage.? I understand that *most* people won't use it that way, but as a library designer, I want to patch all the holes, and make the API as tight as possible.? I want code that uses the library to read as naturally as possible.? So I might rename the function "readTo" to ensure the verb status of "read."? To me, this is a sucky compromise that feels artificially created by the compiler.
>
> You might have different design goals, and different opinions, but the reality is, we have to choose one way or the other, we can't have both.? Well, we could have both, if we could annotate both styles, but then the question becomes, is it worth complicating the language to have one style over the other.
>
> D should either adopt @property as a strict enforcement, or not have it at all.? Having it half-ass reflects poorly on the language design.
>
>
>>>> Currently I'm pondering whether capitalized factory methods, in
> order to mimic ctor syntax, would be an acceptable design. I doubt anyone would every have tried s.Seconds = 5, and thanks to auto, I also doubt anyone would call TimeSpan.Seconds s. And unlike (an impure) s.seconds = 5, TimeSpan.Seconds s; simply doesn't compile. Plus, it self-documents the factory concept in the name.
>>>
>>> If you used C# regularly, where everything is capitalized, you might
> expect capitalized method names and properties.? But in any case, why is capitalization more of a distinguisher than parentheses or lack thereof?
>>
>> Capitalization in D and other languages is generally used for user defined
> types (structs/classes)[1], while variable, field and method names use camelCase or under_scores (i.e. they start with a lower case). The primary exception to this are constructors, which used the type name and therefore are capitalized. Since a factory method is conceptually identical to a constructor, capitalizing factory methods provides an innate understanding of what the method does, what it is used for and how you should call it, to both the corder and code reviewer. Mandated parenthesis, on the other hand, allows the code reviewer only to understand that it is an action, not what type of action it is and the for coder to get a compiler error when they misunderstand, because the API is poorly designed, what the method does, what it is used for and how you should call it.
>>
>> [1] Of course, sometimes UDTs use lower case, like float3, to make them feel
> more like built-in types.
>
>
> C# is drastically different.? Capitalization is used for all methods, all custom types, and properties.? I can't say I like that style, but that's the style.
>
> See here: http://msdn.microsoft.com/en-us/library/x2dbyw72%28v=vs.71%29.aspx
>
>
> In neither C# nor D are these rules enforced by the compiler.? BUT, the decision to capitalize or not is up to the library designer, *not* the caller, and the compiler *does* enforce capitalization as decided by the library designer.? This is a large difference from loose properties, where the caller gets to decide the semantics, not the library designer.? All the library designer can do is try and pick names (which he can control) that make one syntax look utterly horrific.
>
> And that is my point, the library designer is forced to exclude some names that might be unconfusing (if the usage was enforced) in order to compensate for the possibility that the user uses the code the wrong way.
>
> It's like having a car with a switch that goes from two wheel drive to one wheel drive.? And then in order to persuade the driver to not use that switch, you make the car beep annoyingly if they engage the swtich to one-wheel drive.? The better design is to not include the switch at all.
>
> -Steve
>
|
April 25, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | ----- Original Message ----- > From: Robert Jacques <sandford at jhu.edu> > To: Discuss the phobos library for D <phobos at puremagic.com> > Cc: > Sent: Saturday, April 23, 2011 1:05 AM > Subject: Re: [phobos] Time to get ready for the next release > > On Fri, 22 Apr 2011 07:59:54 -0400, Steve Schveighoffer <schveiguy at yahoo.com> wrote: >>> From: Robert Jacques <sandford at jhu.edu> >>> To: Discuss the phobos library for D <phobos at puremagic.com> >>> Sent: Thursday, April 21, 2011 4:05 PM >>> Subject: Re: [phobos] Time to get ready for the next release >>> >>> On Thu, 21 Apr 2011 15:57:57 -0400, Jonathan M Davis > <jmdavisProg at gmx.com> wrote: >>> >>>>> How about the amount of existing code it breaks?? How about the > fact that >>>>> it breaks using the same function for both method chaining and > with >>>>> property syntax? >>>> >>>> Something like >>>> >>>> auto b = a.prop1.prop2.prop3; >>>> >>>> should work. I doesn't at present, but it should. There's a > bug report on it. >>> >>> What about auto b = a.prop1(5).prop2(6).prop3(7); ? >> >> Looks like a poor design.? If a setter property returns anything, it should > return the value set.? Otherwise: >> auto b = a.prop1 = 5; // I would expect b == 5 > > I both David and I have responded in depth to this in other threads. In short, trying to decide the goodness of an API design using an abstracted, out of context, reduced code snippet designed to highlight the syntactic constructs it uses is fallacious. For you to reject my rebuttal of your obviously abstract example by saying my rebuttal is too abstract is also fallacious. David did bring up his library, and it works pretty well with the dual property/function API, but there are some parts that could be used incorrectly, and I pointed those out. >> my solution: >> >> define a setProp1, setProp2, and setProp3 without property semantics.? It > also reads better: >> >> auto b = a.setProp1(5).setProp2(6).setProp3(7); > > However, in the real API, setProp is a strictly inferior design. In point of fact, your proposed solution suffers from several issues: > > 1) It isn't DRY (Don't Repeat Yourself). Not only do you have simple code duplication, but you also have to maintain equality of implementation, not just bug updates. This isn't quite true, the setX is simply a wrapper for the property setter: typeof(this) setX(int newval) { x = newval; return this; } This can be reduced to a mixin. > 2) You've increased the radius of comprehension of your library. Users have to remember that both functions do the same thing and have to assign two different names to the action in their head and then use them appropriately in there code, based on the syntax they wish to use. No they don't.? This is a common argument against larger APIs.? I know many many APIs where I don't *know* the whole API, I just know what I need to get my work done, and lookup anything else.? If you want to use the setX version all the time, there is no need to learn the property functions.? In fact, there is no more learning required for the setX version and the dual property/function version -- both have the same number of API calls. Bottom line, increasing the number of documented calls does not make it harder to learn one of those calls. > 3) If setProp actually read better in real life, we'd use it. But it doesn't, so we aren't. By the way, I would hazard that setX/getX are one of the most famous/infamous pieces of API design out there and that everyone can/does consider it. Your opinion.? I have used it, and have had no complaints. >>>> As for breaking existing code, _of course_ it's going to. > That's to be >>>> expected, and I would have thought that that was expected when > @property was >>>> introduced in the first place. >>> >>> Actually, no it wasn't expected. @property was introduced with > loose semantics, not strict semantics. And, by the way, it was judged worth while with only loose semantics. >> >> I don't know what messages you read, but strict properties were what > was approved.? There have been numerous discussions on the NG regarding properties, some pro-strict, some pro-loose, but the one which got the deal done was pro-strict. > > I've been following/part of the 'property' discussions from day 1. My memory was that @property was 'accepted' inside a pro-strict thread, but wasn't pro-strict itself, and that there was a follow-up confirmation of loose-ness. But, alas, I've deleted my own local newsgroup history and my search-fu is weak. So I can't even find any kind of 'acceptance' post let alone it's context and follow-up. About the best I could find, one way or the other, is a bunch of circumstantial posts indicating the desire to patch a hole, as opposed to replacing the ship. But that could just have been earlier in the decision process. Anyways, my searching did turn up some apropos comments from Andrei: Andrei has always been against properties from day one, there is no secret on that. I seriously doubt Andrei would put properties as being strict into TDPL unless that was the intention. BTW, I searched using opera news (I have the entire news archive on my laptop, well, headers at least), and I could not find where the decision was made to include @property, but it seems it was added to the compiler on 12/2009, and the decision was made somewhere between August of that year and December. >> Without strict properties, the author of the code cannot enforce usage > semantics, and therefore, will lead to ambiguities.? The only exception I can see is calling a function with no arguments which returns void without the parentheses.? It cannot be mistaken for a property getter, because it can't be used as a getter. > > Could you please present an example of an ambiguity in the general case? (i.e. excluding assignment to const/immutable/(static pure) functions and the delegate() foo(){}) I mean semantic ambiguity, not compiler ambiguity.? I mean, the choice of how the symbol can be used makes the symbol name ambiguous where it wouldn't be if the usage was locked to one way or the other. -Steve |
April 25, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques |
----- Original Message -----
> From: Robert Jacques <sandford at jhu.edu>
> To: Steve Schveighoffer <schveiguy at yahoo.com>; Discuss the phobos library for D <phobos at puremagic.com>
> Cc:
> Sent: Saturday, April 23, 2011 1:28 PM
> Subject: Re: [phobos] Time to get ready for the next release
>
> On Fri, 22 Apr 2011 15:26:51 -0400, Steve Schveighoffer <schveiguy at yahoo.com> wrote:
>> Actually, I think you are right.? I wasn't thinking about dmd erroring
> on a statement that does nothing.? You'd have to assign something to the expression, like:
>>
>> auto x = s.seconds = 5;
>>
>> Which still looks like it does something else, but is much less likely to
> occur.
>>
>>
>> You wouldn't need the parameter to be immutable, because the parameter
> is a value, making this a strong-pure function.
>>
>>
>> But this is still not an argument against strict properties.
>
> You were making an argument for strict properties, via actual bug reports (which I commend you on), and I was making a counter-argument to your argument.
>
What I meant was, the technicality that the function could be pure, and that would remove the possibility of using it the "wrong way" does not invalidate the property problem.? In fact, it does not necessarily invalidate the example, since it is D1 we are talking about here (Tango).
-Steve
|
April 25, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques |
----- Original Message -----
> From: Robert Jacques <sandford at jhu.edu>
> To: Steve Schveighoffer <schveiguy at yahoo.com>; Discuss the phobos library for D <phobos at puremagic.com>
> Cc:
> Sent: Saturday, April 23, 2011 1:42 PM
> Subject: Re: [phobos] Time to get ready for the next release
>
> On Fri, 22 Apr 2011 15:26:51 -0400, Steve Schveighoffer
> <schveiguy at yahoo.com> wrote:
> [snip]
>> Another analogy I like to draw upon is casing.? What if D's casing was
> insensitive?? That is, ReadValue is the same thing as readValue and readvalue .? There are probably many people who would love to always use their learned conventions for calling your code (e.g. I always make methods upper case), but then someone comes along and types in reAdvalue (my super-uncreative brain can't come up with a clever example to show something worse, but you get the idea).? The name is the same, but the casing makes all the difference to interpreting what it means!? Like it or not, the same thing applies to things like:
>>
>> writeln = "hello";
>>
>> Even though we know this is not the right way to call it, the compiler
> doesn't give an error to enforce the semantics.
>
> The user is aways right. As a library designer, the user is your customer. And if they discover a new (and meaningful to them) way to use your code, take it as a chance to iterate in a new feature (or improve the design if it's a bug).
It's impossible to improve the design when the compiler doesn't let you enforce your design!
And no, the user is not always right.? That's why we have the compiler to tell them so ;)
-Steve
|
April 25, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | ----- Original Message ----- > From: Robert Jacques <sandford at jhu.edu> > To: Discuss the phobos library for D <phobos at puremagic.com> > Cc: > Sent: Sunday, April 24, 2011 12:03 PM > Subject: Re: [phobos] Time to get ready for the next release > > On Sun, 24 Apr 2011 07:33:30 -0400, Jacob Carlborg <doob at me.com> wrote: >> If writeln = "foo"; doesn't compile but printf = > "foo"; does then I would consider it not fixed. The way I would want @property to behave is disallow bar = "foo"; for functions not marked with @property. But still allow functions not marked with @property to be callable without parentheses. > > Also, this and another post have given me an idea: what if non- at property methods could be assigned to if and only if a valid 'getter' also existed. This would still 'fix' writeln = "foo" but be a less restrictive than an outright ban. It was an idea that Andrei brought up (before @property syntax was introduced), but I don't think it can be properly enforced: int select(int timeout = 0); // both "getter" and "setter" -Steve |
April 25, 2011 [phobos] Time to get ready for the next release | ||||
---|---|---|---|---|
| ||||
Posted in reply to Robert Jacques | On 24 apr 2011, at 18:03, Robert Jacques wrote: > On Sun, 24 Apr 2011 07:33:30 -0400, Jacob Carlborg <doob at me.com> wrote: >> On 23 apr 2011, at 23:20, Robert Jacques wrote: >>> On Sat, 23 Apr 2011 16:06:35 -0400, Jacob Carlborg <doob at me.com> wrote: >>>> On 23 apr 2011, at 17:32, David Simcha wrote: >>>>> On 4/23/2011 11:24 AM, Jacob Carlborg wrote: >>>>>> I think I would like to have something in the middle of strict and loose semantics. I would like that functions marked with @property have to be called like a field: >>>>>> >>>>>> auto bar = foo.field; >>>>>> foo.field = 3; >>>>>> >>>>>> But functions not marked with @property still can be called without the parentheses: >>>>>> >>>>>> foo.bar(); >>>>>> foo.bar; >>>>> >>>>> Maybe there's been some misunderstanding, but actually this is what loose semantics means. Loose semantics (at least as I understand them) mean stuff marked @property would not be callable using method syntax, and this rule would be used to disambiguate the corner cases, but nothing would change for stuff not marked @property. >>>> >>>> Ok, then I probably misunderstood. What about: >>>> >>>> writeln = "foo"; >>>> >>>> is that already fixed? >>> >>> If by fixed, you mean doesn't compile, then yes, it's fixed. But this might be a quality of implementation issue, regarding method syntax and templates and not a true theoretical fix. Case in point: printf = "foo" works. However, while ugly, neither writeln = "foo" nor printf = "foo" are doing something the original author didn't intend. The greater violators (which actually caused bug reports/confusion) are those where the statements became nonsense, like math_function = 5 or obj.factory_method = 6.[1] Fixes for most of these issues exist: Not using the result from a strongly pure function should be an error, not matter how it's called. And const/immutable methods shouldn't be assignable, since you can't assign to a const or immutable variable. Static/free functions can't be marked const/immutable, but considering the only thing they can modify is global state, pure is equivalent. So neither strongly nor weakly pure functions should be assignable. >> >> If writeln = "foo"; doesn't compile but printf = "foo"; does then I would consider it not fixed. The way I would want @property to behave is disallow bar = "foo"; for functions not marked with @property. But still allow functions not marked with @property to be callable without parentheses. > > I have not heard this particular combination before; thank you. More choices are always appreciated. There are real, practical use cases for not- at property methods with write-only field semantics, which this would prevent. And between a real use case and a synthetic straw-man, I believe the use case should win. However, I am interested in any of the practical issues which inspired writeln = "foo", if you know of any. I don't know if there is an issue with writeln = "foo" other than that it can be confusing and looks very odd. > Also, this and another post have given me an idea: what if non- at property methods could be assigned to if and only if a valid 'getter' also existed. This would still 'fix' writeln = "foo" but be a less restrictive than an outright ban. Hm, it sounds like a strange rule, I don't know, it could work. > _______________________________________________ > phobos mailing list > phobos at puremagic.com > http://lists.puremagic.com/mailman/listinfo/phobos -- /Jacob Carlborg |
Copyright © 1999-2021 by the D Language Foundation