January 28, 2013
On 1/28/13 11:21 AM, deadalnix wrote:
> On Monday, 28 January 2013 at 15:44:28 UTC, Andrei Alexandrescu wrote:
>>> Phobos is kind of fucked up in this regard.
>>
>> I understand how you feel though you probably are overstating it. No
>> language can please everyone, and nobody will be pleased by all
>> aspects of a language.
>>
>
> Yes that is probably overstated. But please consider that this state of
> thing in phobos comes from the lax property enforcement in the first
> place, which mitigate greatly your argument about phobos codebase.

I don't see how that computes. We started from lax rules. Then we had somewhat stronger rules, and I personally saw no benefit. I fail to see how it follows that even stronger rules would help there.

Andrei
January 28, 2013
On 1/28/13 11:58 AM, Steven Schveighoffer wrote:
> On Mon, 28 Jan 2013 08:20:23 -0500, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> One interesting fact is that we have evidence at hand. Optional parens
>> _exist_ today in D, and have for a while. The language has worked.
>> They haven't been a disaster.
>
> I've seen some issues, but mostly for allowing normal functions as setters.

Agreed (I consider that feature distinct from optional parens).

> I would be perfectly fine ONLY defining @property on setters, and
> getters where the parentheses are confusing (i.e. getting a
> delegate/function pointer/functor).
>
> I would be fine with D CANCELLING @property as long as we had something
> like Objective C, where the function form of a setter CANNOT be mistaken
> for a normal function. In this case, we would have to live with delegate
> properties requiring two sets of parentheses.
>
> But if you get rid of @property and we are back to D1-style properties,
> please acknowledge that the abuse of functions as setters is not a good
> situation.

Agreed.


Andrei
January 28, 2013
On Monday, 28 January 2013 at 08:34:53 UTC, Jacob Carlborg wrote:
> On 2013-01-28 03:25, Zach the Mystic wrote:
>
>> I first saw UFCS and optional parentheses in Ruby and it seemed both
>> alluring and deceptively simple.
>
> First, Ruby doesn't have UFCS. You can add a new method to any existing class but it's still not UFCS in the same way as D.

Yeah, simply another point of ignorance on my part. Ruby still is remarkable for its syntax. When I looked at it and then I look at what D does with these fancy features, I saw a similarity. Like a double take: where are the parentheses? Where are the arguments? I didn't know then and I don't know now what the fine-grained implications of doing this are.

January 28, 2013
Steven Schveighoffer had mentioned the interesting point that you may want *mandate* the use of parentheses. This is easily solvable with another opXXX function, which I name opDo. Just to illustrate with ordinary structs:

struct Foo
{
  int opDo() { return 4; }
}
Foo foo;

foo; // Error: a struct with opDo must be called with parentheses
January 28, 2013
On 2013-01-28 14:28, Andrei Alexandrescu wrote:

> I agree optional parens take getting used to.

I think it was easy to get used to. Now it's instead harder to use other languages which doesn't allow optional parentheses.

-- 
/Jacob Carlborg
January 28, 2013
On Monday, 28 January 2013 at 19:37:40 UTC, Jacob Carlborg wrote:
> I think it was easy to get used to. Now it's instead harder to use other languages which doesn't allow optional parentheses.

yes
January 28, 2013
On 01/28/2013 01:34 AM, Artur Skawina wrote:
> On 01/28/13 00:23, Timon Gehr wrote:
>> On 01/27/2013 07:12 PM, Artur Skawina wrote:
>>> ...
>>> While it's true that "counter-example" is not the best way to describe the issue,
>>> it /is/ something that is worth considering. And I say that as somebody who was
>>> (and still is) arguing for keeping the last pair of (),
>>
>> You can do that in any case.
>>
>>> because they carry important info for the person /reading/ the code,
>>
>> Often that is not the case.
>
> Hmm, let's try an example.
> Imagine a project, which defines a set of reasonable policies, such as:
>
> Properties may not:
>   - allocate memory
>   - grab locks
>   - block
>   - throw exceptions
>   - cause unexpected changes to the program flow (eg no thread ops)
>   - etc
>
> Now you only need to make sure that these are followed, either via reviews
> and audits, or some checking tool. But once you're reasonably sure that this
> is done, you can reason about code, without having to either know or check
> absolutely everything - which simply does not scale.

As long as there is no actual proof, you still need to take all those cases into account. If you think otherwise, I do not see why you believe that anyone on such a project would leave off the parens when they should not be in order to make the above conventions visible at the call site.

> So a block like
>
>     {
>         auto lock = grab.some.lock();
>         if (a && b && c.d)
>            e = f;
>     }
>
> is then safe from certain class of bugs.
>

Not yet. You missed the potential memory allocation, lock, blocking operation, thrown exception and thread op in e's opAssign.

> Now welcome the ()-less calls to the party, and you've lost important
> information - when auditing you need to make sure that 'a' doesn't
> contain a blocking call, does not allocate, does not violate locking
> rules etc. Ditto for 'b', 'c', 'c.d', 'e' and 'f'. And everything that
> these expressions may call, potentially many levels deep.
>

Add another policy that states that this must not be necessary. Why force your strange conventions on eg. me, who does not even use Exceptions, locks, blocking operations or thread ops and does not need to tightly control memory allocations beyond some global performance considerations, because eg. out of memory does never have too worrisome consequences?

And another one about identifier naming. 'a', 'b', 'c', 'c.d', 'e', 'f'?

> Yes, the "proper" way to handle this is using attributes,

Yes.

> but that is not possible now, nor will it be in the near future.

Well, you already bring forward the possibility of having a checking tool.

> OTOH @properties
> are already available and in combination with enforcing () on all
> other calls can often be used in their place.
>

And there are quite a few other ways to achieve the same thing.

> Allow parens-less calls, and suddenly the value of having @property
> drops significantly, almost to the point that they can be eliminated.

Your policies can still be applied, if you like.

> This is why the optional-parens debate is /directly/ related to
> @properties.
>

As far as I am concerned, @properties are mostly sugar most of which is not implemented yet.

> And this is just one example.
>
>>> but only save one or two keystrokes for the writer. ...
>>
>> Again. It is not about saving keystrokes.
>
> OK, so what is the rationale?

Reading the code. Less noise, compactness of UFCS-chains.
Note that I always add () when leaving them off does not help, eg. for simple method calls.

> I'll say upfront that syntax isn't
> nearly as important as the ability to reason about code;

They obviously go hand in hand. But "reasoning" about code that refers to definitions one is not aware of any specifications of is just rambling anyway.

Also, it is not necessarily good practice to write code that is easier to reason about given a handful policies speaking about global program state. The problem should be decomposed in a sane way and the concerns kept separate instead.

> syntax is something one can get used to, lost information is gone.
>

No information is lost. It's you who defined that any information is carried at the call site.
January 29, 2013
On Monday, 28 January 2013 at 17:00:58 UTC, Andrei Alexandrescu wrote:
> I don't see how that computes. We started from lax rules. Then we had somewhat stronger rules, and I personally saw no benefit. I fail to see how it follows that even stronger rules would help there.
>

That is not complicated. Lax property enforcement => property everywhere.

Then switching to stronger enforcement, property everywhere => bunch of extra annotation for no benefice.

The damage was already done.
January 29, 2013
Just for kicks I decided to rewrite std.array.front in the way my suggested syntax would define it. there are two overloads. With comments removed, the current code is:

//---- Code ----
@property ref T front(T)(T[] a)
if (!isNarrowString!(T[]) && !is(T[] == void[]))
{
    assert(a.length, "Attempting to fetch the front of an empty array of " ~
                     typeof(a[0]).stringof);
    return a[0];
}

@property dchar front(A)(A a) if (isNarrowString!A)
{
    assert(a.length, "Attempting to fetch the front of an empty array of " ~
                     typeof(a[0]).stringof);
    size_t i = 0;
    return decode(a, i);
}
//---- End -----

With what I am calling Highlander structs ("there can be only one"), it would look like this:

//---- Code ----
front struct
{
  ref T opGet(T)(T[] a)
  if (!isNarrowString!(T[]) && !is(T[] == void[]))
  {
      assert(a.length, "Attempting to fetch the front of an empty array of " ~
                       typeof(a[0]).stringof);
      return a[0];
  }

  dchar opGet(A)(A a) if (isNarrowString!A)
  {
      assert(a.length, "Attempting to fetch the front of an empty array of " ~
                       typeof(a[0]).stringof);
      size_t i = 0;
      return decode(a, i);
  }
}
//---- End -----

Three things stood out to me:
1. The identifier "front" only appears once now, prominently at the top of all the definitions.
2. Definitions of "front" cannot be scattered willy-nilly throughout the file anymore.
3. Without @property, the signatures are shorter, and the only price paid is the three extra lines it takes to wrap the whole thing with "front struct { ... }".

I don't think this is a bad exchange at all, considering you now have all the semantics of structs at your disposal for absolute total control over the look and feel of your properties.


January 29, 2013
Sorry if the code comes across funny in the browser. It looked fine in the window I typed it in. ^_^