On Thursday, 24 January 2013 at 08:35:01 UTC, Walter Bright wrote:
This has turned into a monster. We've taken 2 or 3 wrong turns somewhere.

My 2 cents on this, very late in the day. Sorry for the essay, hopefully it'll be worth your time.

No fancy new ideas, but I *think* I have a nice solution that keeps everyone happy and avoids nasty corner-cases and ambiguities:


1) non-property functions must be called with parenthesis, *except* on UFCS calls. No assignment call syntax for non-properties.
  fun1.fun2; //illegal
  fun1.fun2(); //illegal
  fun1().fun2; //OK
  fun1().fun2(); //OK
  fun1; //illegal
  fun1(); //OK
  fun2 = var; //not a function call, but a normal assignment where
              //possible, e.g. initialising a function pointer.
  iota(100).map!"a+1".filter!"a%5".writeln;   //LEGAL :-)

Alternative way of saying it: optional paren for single argument calls in UFCS, enforced parenthesis elsewhere.

Reason: No one wants writeln = "Hello World!"; but a lot of people want "Hello World!".writeln; Also, this removes visual ambiguity between the name of a function and it's result. That only really matters with alias/variadic template parameters but it is very annoying there. That will never conflict with UFCS so everyone's happy. Note that in the first two examples, fun1 is *NOT* a UFCS call and therefore cannot be done without parens. Preventing optional parens on non-UFCS stops any possible mixing of optional parenthesis and the unary & operator.


2) @property enforces parenthesis-less calling for getters and assignment syntax for setters. No properties with more than one argument allowed. If a property returns a callable, any parenthesis will be applied to the callable

Reason: Properties are not for general purpose work. The whole point of them is to be used roughly like variables and this is as close to that as we're gonna get.


3) Getting the address of a function is done with the & operator. Callables must always have parenthesis *except* when: Parenthesis would be optional for an equivalent normal function AND not when the callable is the result of an expression:
  42.aDelegate.foo; //OK
  42.returnsADelegate.foo; //OK, foo acts on the delegate
  42.returnsADelegate().foo; //OK, foo acts on the delegate
  42.returnsADelegate()().foo; //OK, foo acts on
                               //the return value of the delegate
  aDelegate; //illegal
  aDelegate() //OK
  "blah".aDelegate; //OK
  "blah".aDelegate(); //OK

  auto a = &returnsADelegate; //a is function pointer to
                              //returnsADelegate
  a; //illegal
  auto b = a(); //OK, calls a and b is a delegate
  b; //illegal
  b(); //OK, calls the delegate.

  //given some struct Bar that overloads opBinary!"+" and opCall
  Bar x,y;
  x; //illegal
  x(); //opCall
  (x+y)  //does not call opCall
  (x+y)() //does call opCall

Reason: This allows them to be used transparently like normal functions where possible, but removes ambiguity elsewhere.

3a) Explicitly taking the address of a property. Attempting to shoe-horn this in with normal syntax causes hell for the rest. I suggest some magic here, e.g. __traits(propertyGetterAddress, a.prop) and __traits(propertySetterAddress, a.prop) A function pointer to a property must be called as a normal function pointer.

  auto v = __traits(propertyGetterAddress, a.prop);
  auto n = v; //n is a function pointer to the getter a.prop,
              //same as v
  auto n = v(); //n is equal to the return of the getter a.prop

  auto h = __traits(propertySetterAddress, a.prop);
  auto j = h; //j is a function pointer to the setter a.prop
              //same as h
  h = 3; //illegal
  h(3); //OK, equates to a.prop = 3;

Reason: This needs to be possible, but using & for it is broken. The most important thing is to keep the syntax of common use-cases clean and unsurprising. ***any other workable syntax for this is ok, __traits is just an (ugly, verbose) example*** Losing all property-ness when working through a function pointer keeps things simple.


4) OPTIONAL: Free functions can be marked as properties, with the same rules applied to them as properties in aggregates, except they must take 1 or 2 arguments instead of 0 or 1.

Reason: Free functions and ufcs => good for encapsulation and nice to look at. Is there any reason why not to allow us to declare free properties?


These rules should provide the least possible surprise and breakage, as far as I can tell. I don't think personally I would have to alter a single line of my code.

What inevitable corner-cases have I missed?

Reply via email to