April 23, 2011
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?

-- 
/Jacob Carlborg

April 23, 2011
On 23 apr 2011, at 04:36, Robert Jacques wrote:
> Actually, seamlessly switching between field and field-like methods isn't a design goal of 'properties'. The actual design goal is to allow the promotion of a field into a member function. Once that occurs, you can never go back, due to method overloading. In fact, OOP concerns were one of the major driving forces behind 'properties' in the first place.

If I'm not mistaken you can switch between public fields and properties in Scala. Because in Scala public fields are implemented as methods, that is, properties.

-- 
/Jacob Carlborg

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/phobos/attachments/20110423/a4bb1d3a/attachment.html>
April 23, 2011
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.
April 23, 2011
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.

>> Forth, came the realization that in D2 'seconds' would probably be pure, which would cause s.seconds = 5 to be compiler error.
>
> No, it wouldn't be an error.  s.seconds(5) is exactly the same as TimeSpan.seconds(5), both would be callable as pure functions.  In other words, s isn't actually passed to the function, it's just used as a namespace.
>
>
>> 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.
April 23, 2011
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.

April 23, 2011
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).
April 23, 2011
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?

> _______________________________________________
> phobos mailing list
> phobos at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos

-- 
/Jacob Carlborg

April 23, 2011
That's what the pull requests are for.

Anyhow, if someone wants to post a link on the D n.g. for the purpose of collecting usage experience with it, that'd be great!

On 4/23/2011 8:26 AM, Jacob Carlborg wrote:
> Why can't something like this be available on the D website?
>
> On 21 apr 2011, at 19:09, Walter Bright wrote:
>
>>
>> On 4/21/2011 6:24 AM, Michel Fortin wrote:
>>> I'm just wondering how many DMD release will pass before my "const(Object)ref" pull request for DMD get reviewed. I don't want to push Walter too much, but the more he waits the more likely it won't merge so easily.
>>>
>> I understand. My current priority is to get temp destruction to work right. Following on is fixing fundamental issues with const, and getting disabling of default construction to work.
April 23, 2011
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.

 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.
April 23, 2011
> 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.

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.

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.

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.

- Jonathan M Davis