View mode: basic / threaded / horizontal-split · Log in · Help
July 19, 2008
Omittable parens is an evil
Sure, it's a handy feature for properties, but it is a source of too many  
bugs. I think that it is against the D design of avoiding features that  
are error-prone.

Today I once again came across with a problem with them and it's still  
open:

class Test
{
   void test() {}
}

How do I get a mangle of Test.test?

writefln(Test.test.mangleof);    // Should be ok, but prints v, which is  
not what I need
writefln((&Test.test).mangleof); // prints PFZv, which is a pointer to  
function
writefln(__traits(getMember, new Test(), "test").mangleof); // prints v  
(void, return value)

If you have other suggestions, please say, I need the solution. Custom  
mangling is not an option.

The following example was shown in bugzilla and it once again proves that  
ommitable parens lead to errors:

void main()
{
    int run()
    {
        // do the stuff
        return 0;
    }

    Thread thread = new Thread(run);  // run -> &run, this(int) is called  
instead of this(int delegate() dg).
}

Why not have special syntax for properties, like:

class Array(T)
{
   property T* ptr()
   {
      return _ptr;
   }

   property int length()
   {
       return _length;
   }

   void resize(int newSize)
   {
       // code here
   }

   int capacity()
   {
       // code here
   }

   private int _length;
   private T*  _ptr;
}

Usage:
Array!(int) array = new Array!(int);
int len = array.length;
array.resize = 100;       // forbidden
int capacity = array.capacity(); // okay

It is a breaking change, sure, but it solves the design flaw and fix is  
trivial.
July 19, 2008
Re: Omittable parens is an evil
On Sat, 19 Jul 2008 15:32:36 +0200, Koroskin Denis <2korden+dmd@gmail.com>  
wrote:

> Why not have special syntax for properties, like:

This has come up multiple times - that's one of the few things where C#  
wins over D. If I may repeat a suggestion I made once, maybe Walter can be  
hypnotized into implementing it if I just repeat it often enough :)

class foo
{
    private int _bar;
    property int bar
    {
        opGet() { return _bar; }
        opSet(auto value) { _bar = value; }
        opAddAssign(auto value) { _bar += value; } // it's extremely  
extendable!
    }
}

-Mike

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
July 19, 2008
Re: Omittable parens is an evil
"Mike" <vertex@gmx.at> wrote in message news:op.uejk9fs8kgfkbn@lucia...
> On Sat, 19 Jul 2008 15:32:36 +0200, Koroskin Denis <2korden+dmd@gmail.com> 
> wrote:
>
>> Why not have special syntax for properties, like:
>
> This has come up multiple times - that's one of the few things where C# 
> wins over D. If I may repeat a suggestion I made once, maybe Walter can be 
> hypnotized into implementing it if I just repeat it often enough :)
>
> class foo
> {
>     private int _bar;
>     property int bar
>     {
>         opGet() { return _bar; }
>         opSet(auto value) { _bar = value; }
>         opAddAssign(auto value) { _bar += value; } // it's extremely 
> extendable!
>     }
> }
>
> -Mike

I've always been in favor of this sort of thing as well. My reasoning is 
that "member variable" vs "getter/setter function" is an implementation 
detail, and implementation details should be possible to abstract away.

The creator of a library/API/etc should be able to design their classes in 
way such that if a class has a property (for instance, the color of it), 
then the user of the object wouldn't have to stop and think "Ok, now is 
color accessed as a member variable or through getters/setters?". The 
library creator should be able to make it so that it's the same either way.

Additionally, the ability to abstract away the "member variable" vs 
"getter/setter function" distinction would allow a library/API creator to 
develop like this: When first creating a class, the class has a property 
"x". At this point in time, there's nothing special that needs to be done 
when "x" is read from or written to. So implementing "x" as a member 
variable is perfectly sufficient. Later on, the class gains enhancements, 
some of which require additional actions to be taken whenever "x" is 
accessed. You're working on a library/API, so you don't want this change to 
be a breaking one. So instead of needing to religously implement all trivial 
and non-trivial properties as getters/setters right from day one in order to 
avoid this situation, all you'd need to do is say "Ok, property 'x' now 
needs getter/setter functionlity, so I'll convert it into this special 
'property accessing' feature of the language instead of getter/setter 
functions, and that way my change won't break anything."

A third reason: Project management (Although I really think of this sort of 
thing more as being "lead programmer" than "manager". A manager's role is 
administrative, they're there to make sure the developers have what they 
need to do their job - chairs, computers, tools, distraction-free workspace, 
competent co-workers, etc. It's not their role to go sticking their fingers 
into the code. But I digress.). Just like how the built-in unittests, 
documentation, invariants, and debug conditionals allow...whoever is in 
charge...to have one less thing to arbitrarily define in their "coding 
standards", this would alliviate the need to define a standard naming 
convention for getters/setters. Whatever standard variable naming convention 
exists would be sufficient.

So, four reasons for a special "property accessing" syntax like the above:

1. The "member variable" vs "getter/setter function" distinction is an 
implementation detail, and as such, should be possible to abstract away.

2. User of a library doesn't always have to think "Ok, now is this property 
implemented as a member variable or as getters/setters?".

3. Creator of a library can change a member variable into a "getter/setter" 
of sorts without it being a breaking change, and without needing to 
religously implement all properties as getters/setters from day one.

4. Lead developer doesn't have to come up with an arbitrary "getter/setter" 
naming convention. They can simply say "Just use the built-in 'property 
accessing' syntax, and follow the usual variable naming conventions".
July 19, 2008
Re: Omittable parens is an evil
"Koroskin Denis" <2korden+dmd@gmail.com> wrote in message 
news:op.uejjwmv6n8fdl4@korden...
> Sure, it's a handy feature for properties, but it is a source of too many 
> bugs. I think that it is against the D design of avoiding features that 
> are error-prone.
>
> Today I once again came across with a problem with them and it's still 
> open:
>
> class Test
> {
>    void test() {}
> }
>
> How do I get a mangle of Test.test?
>
> writefln(Test.test.mangleof);    // Should be ok, but prints v, which is 
> not what I need
> writefln((&Test.test).mangleof); // prints PFZv, which is a pointer to 
> function
> writefln(__traits(getMember, new Test(), "test").mangleof); // prints v 
> (void, return value)
>
> If you have other suggestions, please say, I need the solution. Custom 
> mangling is not an option.
>
> The following example was shown in bugzilla and it once again proves that 
> ommitable parens lead to errors:
>
> void main()
> {
>     int run()
>     {
>         // do the stuff
>         return 0;
>     }
>
>     Thread thread = new Thread(run);  // run -> &run, this(int) is called 
> instead of this(int delegate() dg).
> }
>
> Why not have special syntax for properties, like:
>
> class Array(T)
> {
>    property T* ptr()
>    {
>       return _ptr;
>    }
>
>    property int length()
>    {
>        return _length;
>    }
>
>    void resize(int newSize)
>    {
>        // code here
>    }
>
>    int capacity()
>    {
>        // code here
>    }
>
>    private int _length;
>    private T*  _ptr;
> }
>
> Usage:
> Array!(int) array = new Array!(int);
> int len = array.length;
> array.resize = 100;       // forbidden
> int capacity = array.capacity(); // okay
>
> It is a breaking change, sure, but it solves the design flaw and fix is 
> trivial.

I'm not sure if I'm completely following you here. Are you basically saying 
that being able to call function foo by shortening "foo();" into "foo;" 
confuses the issue of whether you're referring to the function itself or 
actually trying to invoke it?

If so, then 1. I should pay more attention because I didn't realize you 
could do that ;). And 2. I agree.
July 19, 2008
Re: Omittable parens is an evil
"Mike" <vertex@gmx.at> wrote in message news:op.uejk9fs8kgfkbn@lucia...
> On Sat, 19 Jul 2008 15:32:36 +0200, Koroskin Denis <2korden+dmd@gmail.com> 
> wrote:
>
>> Why not have special syntax for properties, like:
>
> This has come up multiple times - that's one of the few things where C# 
> wins over D. If I may repeat a suggestion I made once, maybe Walter can be 
> hypnotized into implementing it if I just repeat it often enough :)
>
> class foo
> {
>     private int _bar;
>     property int bar
>     {
>         opGet() { return _bar; }
>         opSet(auto value) { _bar = value; }
>         opAddAssign(auto value) { _bar += value; } // it's extremely 
> extendable!
>     }

I agree, but having to reimplement the opXxxAssign methods for every 
property would quickly become tedious.  A much simpler way to do it is to 
define that:

obj.property op= expr;

is exactly the same as:

obj.property.opSet(obj.property.opGet() op expr);

I believe C# does this.  Still it'd be nice to allow opXxxAssign for 
properties to overload the default behavior, but it'd at least have a 
reasonable fallback.

In the initial designs for MiniD, when it was still a statically-typed 
language, I defined them exactly in this way, and then abstracted the idea 
by having a 'namespace' construct which could be used to implement 
properties, group symbols logically, and so on.

None of this will ever get into D.
July 19, 2008
Re: Omittable parens is an evil
"Nick Sabalausky" <a@a.a> wrote in message 
news:g5tdll$2sjj$1@digitalmars.com...

> I'm not sure if I'm completely following you here. Are you basically 
> saying that being able to call function foo by shortening "foo();" into 
> "foo;" confuses the issue of whether you're referring to the function 
> itself or actually trying to invoke it?

It's true!
July 19, 2008
Re: Omittable parens is an evil
"Mike" <vertex@gmx.at> wrote in message news:op.uejk9fs8kgfkbn@lucia...
> On Sat, 19 Jul 2008 15:32:36 +0200, Koroskin Denis <2korden+dmd@gmail.com> 
> wrote:
>
>> Why not have special syntax for properties, like:
>
> This has come up multiple times - that's one of the few things where C# 
> wins over D. If I may repeat a suggestion I made once, maybe Walter can be 
> hypnotized into implementing it if I just repeat it often enough :)
>
> class foo
> {
>     private int _bar;
>     property int bar
>     {
>         opGet() { return _bar; }
>         opSet(auto value) { _bar = value; }
>         opAddAssign(auto value) { _bar += value; } // it's extremely 
> extendable!
>     }
> }
>
> -Mike

I'm just kind of brainstorming possible improvements to the usual way of 
doing properties. What if the above were adjusted into something like this 
(there's a few things I've done differently here):

class foo
{
   // Similar to how classes define an implict member "this",
   // "property int bar" defines an implicit "private int bar.value"
   // (Or maybe "protected int bar.value"? Or maybe adjustable somehow?).
   // This 1, elimininates the need to manually create "private _bar"
   // and 2, follows in the spirit of naming all constructors "this"
   // instead of having a different ctor name for each class
   // (and therefore achieves the same benefits - such as easier renaming).

   property int bar
   {
       // "get" and "set" can each be set separately to "public", 
"private", "protected"
       // (Maybe "protected" would be useless, though? Depends if these 
should
       // be overrideable.)
       get { return value; }
       set { value = set; } // The rvalue "set" is an implied param, and
                                  // works just like the implied "value" in 
C#'s setters.

       // Never needed, but possibly allowed just for things like 
performance.
       opAddAssign(auto addend) { value += addend; }
   }
   private func()
   {
        Stdout.formatln("{}", this.bar); // Use property
        Stdout.formatln("{}", this.bar.value); // Sidestep property
   }
}

void main()
{
   int x;
   auto f = new foo();

   f.bar = 5; // ok
   x = f.bar; // ok
   f.func(); // ok, displays "5" twice

   f.bar.value = 7; // Illegal, "bar.value" is private to "foo"
   x = f.bar.value; // Illegal, "bar.value" is private to "foo"

}
July 19, 2008
Re: Omittable parens is an evil
On Sat, 19 Jul 2008 21:03:28 +0200, Jarrett Billingsley  
<kb3ctd2@yahoo.com> wrote:

> "Nick Sabalausky" <a@a.a> wrote in message
> news:g5tdll$2sjj$1@digitalmars.com...
>
>> I'm not sure if I'm completely following you here. Are you basically
>> saying that being able to call function foo by shortening "foo();" into
>> "foo;" confuses the issue of whether you're referring to the function
>> itself or actually trying to invoke it?
>
> It's true!

For me it's mostly that there's a clear _VISUAL_ distinction between "this  
does something" (parens) and "this is data" (no parens); and in D there's  
no difference in this one (arbitrary) edge case. It's easy to "eyeball  
scan" code using parens pairs as visual anchors.

-Mike

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
July 19, 2008
Re: Omittable parens is an evil
On Sat, 19 Jul 2008 21:42:22 +0200, Nick Sabalausky <a@a.a> wrote:

Hey - I like that implicit value declaration very much. However, there  
needs to be a way to declare pseudo properties (without the implicit  
value), so I'd add an initializer to the property:

class foo
{
    property int bar
    {
        value = void; // this is the initial value; void means that there  
is no implicit value
        // here be getters/setters
    }
}

Maybe something like that?

-Mike

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
July 19, 2008
Re: Omittable parens is an evil
"Mike" <vertex@gmx.at> wrote in message news:op.uej2aznskgfkbn@lucia...
> On Sat, 19 Jul 2008 21:42:22 +0200, Nick Sabalausky <a@a.a> wrote:
>
> Hey - I like that implicit value declaration very much. However, there 
> needs to be a way to declare pseudo properties (without the implicit 
> value), so I'd add an initializer to the property:
>
> class foo
> {
>     property int bar
>     {
>         value = void; // this is the initial value; void means that there 
> is no implicit value
>         // here be getters/setters
>     }
> }
>
> Maybe something like that?
>
> -Mike

My thought on that scenario was that if nothing within the "property int 
bar" block actually accesses the implied "value" member (I would think that 
wouldn't be too hard to detect, but maybe I'm wrong), then any access to the 
implied "value" from outside the block would be either completely 
meaningless or a sign that something is being done wrong. So in that case, 
the implied "value" is sort of "optimized away" (in a mannar of speaking, 
since it's not exactly the same as normal "optimizing away") and any attempt 
to access it from outside the block becomes an error.
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home