View mode: basic / threaded / horizontal-split · Log in · Help
January 27, 2013
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
Re: Property discussion wrap-up
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
1 2 3 4 5 6
Top | Discussion index | About this forum | D home