January 27, 2013
On 1/27/13 12:37 PM, Dicebot wrote:
> On Sunday, 27 January 2013 at 16:50:47 UTC, deadalnix wrote:
>> Off topic rant.
>>
>> I suppressed a counterexample in the section Optional parentheses
>> - Extra note .
>>
>> The note state that some stuff are valid for *function* and the
>> counter example showed ambiguity using opCall. I don't know who did
>> this and I don't care. I however can't stand intellectual dishonesty.
>
> It was me, sorry if I have offended you. I tend to read "function" as
> "callable" if not mentioned otherwise and thus was wandering how note
> refers to this case. This left counter-example in hope that someone will
> comment it.
>
> Now I see that it should be better suited to discussion, but at that
> time it was just curiosity, not desire to prove anything.

I think we should leave the example somewhere, it's a syntactical case we need to look at. Regarding the original remark, intellectual dishonesty is as damaging as assuming it off-the-cuff.

Andrei
January 27, 2013
On 01/27/13 17:50, deadalnix wrote:
> On Friday, 25 January 2013 at 18:57:17 UTC, Johannes Pfau wrote:
>> But please keep off-topic stuff, offenses and meta discussion(release
>> process, ...) in the newsgroup.
> 
> Off topic rant.
> 
> I suppressed a counterexample in the section Optional parentheses  - Extra note .
> 
> The note state that some stuff are valid for *function* and the counter example showed ambiguity using opCall. I don't know who did this and I don't care. I however can't stand intellectual dishonesty.
> 
> If your ideas are the best one, such mean move shouldn't be necessary to prove your point.

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 (), because they carry important info for the person /reading/ the code, but only save one or two keystrokes for the writer. Removing that example is going too far; this is why a wiki isn't the right forum for a discussion.

Cases like the removed one [1] was actually why I wanted ()-less calls to be opt-in
(by requiring some kind of @chainable attribute) or the introduction of a separate
operator (so that eg "l->r(A...)" means "r(l, A)") as removing ambiguity is always
good. Not that it would completely fix /this/ particular case; for that you'd need
to require the first parens too, or maybe declare that omitting them is only valid
for ufcs calls.

Still, this case is much less of a problem than having /every/ member access potentially be a function call. Just defining that opCalls will never be called here (ie omitting () is only valid for functions) may be acceptable and already an improvement.

artur

[1]

struct Plain
{
    int a;
}

struct Tricky
{
    int a;
    Plain opCall() { return Plain.init }
}

void func(int) { }

// What happens?
Tricky t;
t.a.func();

January 27, 2013
Several suggestions here:

With regard to optional parentheses, it had been suggested that any ambiguity be regarded as an error. This is the example I used:

int foo() { return 4; }
auto x = foo; // Error: gives 4 or gives function foo?

I suggested the ambiguity be resolved thus:

auto x = foo(); // parens to get the return value
auto y = cast(function) foo; // cast(function) gives the function

With regard to @property, Rob T suggested that properties are similar to structs, and Adam D. Ruppe suggested a struct might be definable as a single instance:

struct { ... } foo;

I suggested that the syntax be changed to put the name in front, with the simple switch of the normal "struct foo {}" to:

foo struct {} // No need for trailing semicolon now

All property methods can now be defined as you would for a normal struct, and the new syntax makes this, if I might say so, absurdly easy, assuming it's an unambiguous syntax as I think it is.

An enhancement to enforce the lack of parentheses would be define opGet, which disables opCall and disallows using parens when called:

struct gogo
{
  int _foo;

  // Note the switched tokens: means foo is the unique instance of the struct
  foo struct
  {
    int opGet() { return _foo; } // Enforces no parentheses
    int opCall() {} // Error: a struct may not have both opCall and opGet
  }
}

opGet's companion, opSet, could be syntax sugar for opAssign and opOpAssign, but I'm not sure how it would really work, or if it's even necessary. This:

ref int opSet( int rhs ) { _foo = rhs; return this; }

Could be lowered to something like this:

ref int opAssign( int rhs ) { _foo = rhs; return this; }
ref int opOpAssign( string op ) ( int newFoo ) { _foo = mixin("_foo" ~op~ " rhs"); }

January 27, 2013
On Sunday, 27 January 2013 at 20:22:57 UTC, Zach the Mystic wrote:
> Several suggestions here:
>
> With regard to optional parentheses, it had been suggested that any ambiguity be regarded as an error. This is the example I used:
>
> int foo() { return 4; }
> auto x = foo; // Error: gives 4 or gives function foo?

Unlike C, in D a function is not implicitly converted to pointer to function, and because you cannot create functions as stack variables, that statement should fetch 4.

>
> I suggested the ambiguity be resolved thus:
>
> auto x = foo(); // parens to get the return value
> auto y = cast(function) foo; // cast(function) gives the function

Perhaps you mean function pointer or delegate.

> With regard to @property, Rob T suggested that properties are similar to structs, and Adam D. Ruppe suggested a struct might be definable as a single instance:
>
> struct { ... } foo;

If you mean he suggests to implement properties through structs, than that is discussable, but if you mean that properties are like structs, than I found it is a bad idea, because structs and properties share almost nothing. Struct is an aggregate of objects of different types with methods and property is an abstraction over particular object which should not be accessed directly but through some procedure.

> I suggested that the syntax be changed to put the name in front, with the simple switch of the normal "struct foo {}" to:
>
> foo struct {} // No need for trailing semicolon now
>
> All property methods can now be defined as you would for a normal struct, and the new syntax makes this, if I might say so, absurdly easy, assuming it's an unambiguous syntax as I think it is.
>
> An enhancement to enforce the lack of parentheses would be define opGet, which disables opCall and disallows using parens when called:
>
> struct gogo
> {
>   int _foo;
>
>   // Note the switched tokens: means foo is the unique instance of the struct
>   foo struct
>   {
>     int opGet() { return _foo; } // Enforces no parentheses
>     int opCall() {} // Error: a struct may not have both opCall and opGet
>   }
> }
>

So, solution is to use some unusual struct type as a wrapper on a member type. Why not default directly to real type like:

// in/out were suggested as D naming for getter and setter in the recent thread
struct S
{
    int foo
    {
        in { return ... } // or @set
        out { ...} // or @get
    }
}

Such sort of proposal introduces (like property-struct) significant change to syntax, so why not use fully the opportunity to make the syntax nicer?

> opGet's companion, opSet, could be syntax sugar for opAssign and opOpAssign, but I'm not sure how it would really work, or if it's even necessary. This:
>
> ref int opSet( int rhs ) { _foo = rhs; return this; }
>
> Could be lowered to something like this:
>
> ref int opAssign( int rhs ) { _foo = rhs; return this; }
> ref int opOpAssign( string op ) ( int newFoo ) { _foo = mixin("_foo" ~op~ " rhs"); }

January 27, 2013
On Sunday, 27 January 2013 at 21:03:45 UTC, Maxim Fomin wrote:
>> int foo() { return 4; }
>> auto x = foo; // Error: gives 4 or gives function foo?
>
> Unlike C, in D a function is not implicitly converted to pointer to function, and because you cannot create functions as stack variables, that statement should fetch 4.

Okay, I was ignorant of that, and it's a bad example. I'm not going to pretend I know everything. But the man issue is to make ambiguous cases an error and not silently accepted as one or the other. If there aren't very many, or even any, then great, it's a non-issue.

Thank you for educating me. Also, I thought that cast(function) or cast(delegate) was a clear way of indicating the function, perhaps just a shorthand for &foo or something, but much clearer.

>> With regard to @property, Rob T suggested that properties are similar to structs, and Adam D. Ruppe suggested a struct might be definable as a single instance:
>>
>> struct { ... } foo;
>
> If you mean he suggests to implement properties through structs, than that is discussable,

Yes.

> but if you mean that properties are like structs, than I found it is a bad idea, because structs and properties share almost nothing. Struct is an aggregate of objects of different types with methods and property is an abstraction over particular object which should not be accessed directly but through some procedure.

I may not even know enough to disagree intelligently, but I do disagree with what you say here. I believe structs and properties have a _lot_ in common. Particularly, they are a namespace, which therefore give you the identifier you need to act as if it's real data. They also can overload all important operators so that that name can lurk amongst ordinary code transparently, as is required of properties.

>> struct gogo
>> {
>>  int _foo;
>>
>>  // Note the switched tokens: means foo is the unique instance of the struct
>>  foo struct
>>  {
>>    int opGet() { return _foo; } // Enforces no parentheses
>>    int opCall() {} // Error: a struct may not have both opCall and opGet
>>  }
>> }
>>
>
> So, solution is to use some unusual struct type as a wrapper on a member type. Why not default directly to real type like:
>
> // in/out were suggested as D naming for getter and setter in the recent thread
> struct S
> {
>     int foo
>     {
>         in { return ... } // or @set
>         out { ...} // or @get
>     }
> }
>
> Such sort of proposal introduces (like property-struct) significant change to syntax, so why not use fully the opportunity to make the syntax nicer?

You're right, opGet and opSet are as ugly as all the opXXXXX overloads. They are nonetheless consistent with how operators are already defined, which argues in favor of them. However, "in" and "out" above seem out of place too. I don't have a way to make opGet, opSet look good, but "in" and "out" in the above example are very hard for me to understand, given prior uses of in and out.

Also note that opGet and opSet are unnecessary, that structs can be made to work in a variety of ways. They can store some data or not, act like properties or not, extremely flexibly. Single-instance structs just make structs easier to use in general.

January 27, 2013
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.

> but only save one or two keystrokes for the writer. ...

Again. It is not about saving keystrokes.
January 27, 2013
On 01/27/2013 10:47 PM, Zach the Mystic wrote:
> ...
> Okay, I was ignorant of that, and it's a bad example. I'm not going to
> pretend I know everything. But the man issue is to make ambiguous cases
> an error and not silently accepted as one or the other. If there aren't
> very many, or even any, then great, it's a non-issue.
> ...

In the absence of language rules, every sequence of characters has an ambiguous meaning. It is only ambiguous to you because you seem not aware of the rule that states that free-standing function names are an alternative notation for argument-less calls.
January 27, 2013
On Sunday, 27 January 2013 at 23:29:16 UTC, Timon Gehr wrote:
> In the absence of language rules, every sequence of characters has an ambiguous meaning. It is only ambiguous to you because you seem not aware of the rule that states that free-standing function names are an alternative notation for argument-less calls.

But I'm pretty sure more experienced people than myself had found points of ambiguity in what I'm talking about. Adam D. Ruppe had said something to that effect, and somebody said "typeof(foo)" which tripped Walter up, and I'm pretty sure it's because there really are cases of ambiguity when parentheses are made optional.

Also, strangely enough, people's use of the word ambiguity seems to be ambiguous. What _I_ mean by it is that the _compiler_ finds it ambiguous. I say "clear" if the reader of the program can easily understand what he or she is looking at, and "concise" if the given code is short.

If ambiguity in unused optional parentheses is a non-issue, I'm totally cool with that. In fact, that would be great, proving that optional parentheses are a sound design choice.

What I'm trying to do is make sure that there is no possibility for an ambiguous reading of an expression which silently passes based on some odd rule over which valid case should be chosen. My prototype for this is when the compiler issues an error for ambiguous repeated symbols found in two different modules. Error, not silence. If it simply doesn't apply here, then please, let me know.
January 28, 2013
On 1/27/13 3:22 PM, Zach the Mystic wrote:
> Several suggestions here:
>
> With regard to optional parentheses, it had been suggested that any
> ambiguity be regarded as an error. This is the example I used:
>
> int foo() { return 4; }
> auto x = foo; // Error: gives 4 or gives function foo?
>
> I suggested the ambiguity be resolved thus:
>
> auto x = foo(); // parens to get the return value
> auto y = cast(function) foo; // cast(function) gives the function

I was thinking of just using &foo, like in C.

BTW also regarding optional parentheses, while I was working on https://github.com/D-Programming-Language/tools/pull/41/files I refactored a bit of code to use UFCS and paren-less syntax. I must say I find this a very fluid style of programming that I'd hate to lose.

One more thought - though optional parens and properties are distinct issues, there is some interaction: optional parens reduce the need for @property annotation on read-only properties.


Andrei
January 28, 2013
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. So a block like

   {
       auto lock = grab.some.lock();
       if (a && b && c.d)
          e = f;
   }

is then safe from certain class of bugs.

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.

Yes, the "proper" way to handle this is using attributes, but that
is not possible now, nor will it be in the near future. OTOH @properties
are already available and in combination with enforcing () on all
other calls can often be used in their place.

Allow parens-less calls, and suddenly the value of having @property drops significantly, almost to the point that they can be eliminated. This is why the optional-parens debate is /directly/ related to @properties.

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? I'll say upfront that syntax isn't nearly as important as the ability to reason about code; syntax is something one can get used to, lost information is gone.

artur