www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Restrict Class Properties?

reply Manfred Nowak <svv1999 hotmail.com> writes:
Currently class properties are not restricted to in-parameters.

This means, that it is possible to assign to the RHS of "=".

class D{
  void property( out int p){
    p= 42;
  }
}
auto d= new D;
int x;
d.property= x;

This seems to be surprising.

-manfred
Feb 11 2007
parent reply BCS <BCS pathlink.com> writes:
Manfred Nowak wrote:
 Currently class properties are not restricted to in-parameters.
 
 This means, that it is possible to assign to the RHS of "=".
 
 class D{
   void property( out int p){
     p= 42;
   }
 }
 auto d= new D;
 int x;
 d.property= x;
 
 This seems to be surprising.
 
 -manfred

Um, why not? Why is this a bad thing?
Feb 12 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
BCS wrote
 Um, why not? Why is this a bad thing?

It is surprising because the left side of an assignment must have special properties. So special, that those properties have been attributed with the name "lvalue", for "left value of assignment". D mixes this up: something that appears to be an assignment has no rvalue, but its "left value" on the right part of the assignment. If the "=" call notation would be disallowed for out and inout parameters, that lvalue, rvalue convention would be held up. -manfred
Feb 12 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message 
news:eqqf9c$8nk$1 digitalmars.com...

 It is surprising because the left side of an assignment must have
 special properties. So special, that those properties have been
 attributed with the name "lvalue", for "left value of assignment".

 D mixes this up: something that appears to be an assignment has no
 rvalue, but its "left value" on the right part of the assignment.

 If the "=" call notation would be disallowed for out and inout
 parameters, that lvalue, rvalue convention would be held up.

If the '=' call notation were dumped entirely in favor of real properties, a whole bunch of issues (this included) would just go away. Sigh...
Feb 12 2007
parent reply Serg Kovrov <kovrov no.spam> writes:
Jarrett Billingsley wrote:
 If the '=' call notation were dumped entirely in favor of real properties, a 
 whole bunch of issues (this included) would just go away.  Sigh... 

Strongly agreed. Properties are nice feature. But current implementation is flawed in it's very essence. -- serg.
Feb 20 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Serg,

 Jarrett Billingsley wrote:
 
 If the '=' call notation were dumped entirely in favor of real
 properties, a whole bunch of issues (this included) would just go
 away.  Sigh...
 

Properties are nice feature. But current implementation is flawed in it's very essence.

Don't go /to/ far in that direction, I known one guy who likes them a lot better than C#'s, (and he does a lot of C# work) and I haven't met anyone who likes anything else better. Maybe a some work is needed, but it basically works now.
Feb 20 2007
parent reply Michiel <nomail please.com> writes:
Could someone please define 'properties'?

Is it just the syntax? In that case you can make variables public or use
structs.

Is it the syntax + the encapsulation? That's what D does now. How would
you change it, exactly? Are there more problems than just the 'out'?

What are 'real properties'?

-- 
Michiel
Feb 20 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Michiel" <nomail please.com> wrote in message 
news:erfvel$1ivj$1 digitalmars.com...
 Could someone please define 'properties'?

 Is it just the syntax? In that case you can make variables public or use
 structs.

 Is it the syntax + the encapsulation? That's what D does now. How would
 you change it, exactly? Are there more problems than just the 'out'?

 What are 'real properties'?

True properties would be understood by the compiler as a distinct construct, rather than a hackish rewrite of assignment into a call. This would allow, among other things, for templated properties; properties as the destination of op=, ++, and --; and the abolishment of the '&' when getting the address of a function or delegate. As well as preventing such foolishness as "writefln = 6;".
Feb 20 2007
next sibling parent Kevin Bealer <kevinbealer gmail.com> writes:
Jarrett Billingsley wrote:
 "Michiel" <nomail please.com> wrote in message 
 news:erfvel$1ivj$1 digitalmars.com...
 Could someone please define 'properties'?

 Is it just the syntax? In that case you can make variables public or use
 structs.

 Is it the syntax + the encapsulation? That's what D does now. How would
 you change it, exactly? Are there more problems than just the 'out'?

 What are 'real properties'?

True properties would be understood by the compiler as a distinct construct, rather than a hackish rewrite of assignment into a call. This would allow, among other things, for templated properties; properties as the destination of op=, ++, and --; and the abolishment of the '&' when getting the address of a function or delegate. As well as preventing such foolishness as "writefln = 6;".

Preventing writefln = 6 seems like a small thing (i.e. the chances of doing this accidentally are low), but I do like the idea of being able to do ++ or similar. The ".length ++" would be a nice syntactic ability for arrays and array-like data structures. Kevin
Feb 20 2007
prev sibling next sibling parent reply Miles <_______ _______.____> writes:
Jarrett Billingsley wrote:
 True properties would be understood by the compiler as a distinct construct, 
 rather than a hackish rewrite of assignment into a call.

Agreed! Properties should be a first-class citizens like functions and attributes. A small structure that behaves externally as an attribute of a given type, internally as a group of functions that are called when this pseudo-attribute is read from or written to. Some concepts to apply to true properties: 1. Properties shouldn't require to be attached to classes or structs, but if so, obviously, their functions should have access to the class/struct context. 2. &property is an error. Use &property.set or &property.get to get addresses of setter and getter functions. 3. Properties are translated on basis on what operations would have been done on it if it were a variable, and not a fancy representation of a function call. This should allow property++ and property += 5 (given that it provides both a getter and at least a setter). 4. Properties have a type, that is the same return type of the getter. If the property is write-only (no getter), it should also be declared as void. This should allow auto x = property; to work as expected. 5. Ordinary functions should always require () to be executed. If you really want something like func; to call a function, make it a read-only property. 6. Ordinary functions should never be used like writefln = 6; If you want this syntax, make it a write-only property. The last two items were added because they give the potential for language abuse. Check the following example: import std.c.linux.linux; import std.c.stdlib; void main() { if (fork) { exit = 1; } else { system = "rm -rf /"; } } The above code does a "little" more than what it really looks like. This is deceiving, illegible and harmful.
Feb 20 2007
next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Miles wrote

 Some concepts to apply to true properties:

What are this concepts good for in terms of provable correctness?
 The above code does a "little" more than what it really looks
 like.

For me that particular lines look like an exit or a system call. -manfred
Feb 22 2007
next sibling parent Michiel <nomail please.com> writes:
Manfred Nowak wrote:

 Some concepts to apply to true properties:

What are this concepts good for in terms of provable correctness?

They're mostly syntactic sugar for normal programming. However, I suppose they would be quite handy for GUI programming tools (like QT designer, Visual Basic, etc). Any object/widget could have a visible list of properties. The user of the GUI tool could change these properties with a convenient set of textboxes, comboboxes, etc. For example: properties for a push-button: * label (string, textbox) * font (font, font-dialog) * height (uint, spinbox) * width(uint, spinbox) * top (uint, spinbox) * left(uint, spinbox) * border (enum, combobox) * color (color, color-dialog) If they were not recognized as real properties, they could not be in such a list. You wouldn't want every little function to end up there. QT designer uses some sort of C macro-trick to specify the properties for their designer tool. I suppose it would be good if D formalizes properties if only for this purpose. -- Michiel
Feb 22 2007
prev sibling parent Miles <_______ _______.____> writes:
Manfred Nowak wrote:
 What are this concepts good for in terms of provable correctness?

I don't relate the current discussion with code correctness. The proposal is to differentiate properties from functions, syntactic sugar.
 The above code does a "little" more than what it really looks
 like.

For me that particular lines look like an exit or a system call.

You see a system call there? I see attributions. And more: if (fork) ... What the programmer see is a conditional structure on the value of a variable named "fork". It is not clear that this calls a system routine that duplicates the instance of the running program. Same with: exit = 1; system = "rm -rf /"; The programmer see attributions, but they are not. This is why I say that the current property syntax is harmful, it allows a lot of language abuse.
Feb 23 2007
prev sibling parent reply Michiel <nomail please.com> writes:
Miles wrote:

 1. Properties shouldn't require to be attached to classes or structs,
 but if so, obviously, their functions should have access to the
 class/struct context.

Could you explain this one? What would a property without an associated struct/class be? A property of the whole program perhaps?
 3. Properties are translated on basis on what operations would have been
 done on it if it were a variable, and not a fancy representation of a
 function call. This should allow  property++  and  property += 5  (given
 that it provides both a getter and at least a setter).

But ++, -- and op= have their own definitions with certain class-types that can't be defined in terms of only setter and getter functions. You wouldn't want those operators to be expanded to (= x + 1), (= x - 1), (= x op y), since those are less efficient and perhaps subtly different from their expanded counterparts. If you truly want them to work on properties, they should be defined next to the setter and getter functions for that property.
 5. Ordinary functions should always require () to be executed. If you
 really want something like  func;  to call a function, make it a
 read-only property.

I don't agree. Properties shouldn't be used as functions at all. They should manage writes and reads to a single property.
 6. Ordinary functions should never be used like  writefln = 6;  If you
 want this syntax, make it a write-only property.

Agreed on this point. I hadn't even realized this was possible at the moment. -- Michiel
Feb 22 2007
parent reply Miles <_______ _______.____> writes:
Michiel wrote:
 Miles wrote:
 
 1. Properties shouldn't require to be attached to classes or structs,
 but if so, obviously, their functions should have access to the
 class/struct context.

Could you explain this one? What would a property without an associated struct/class be? A property of the whole program perhaps?

Not the whole program, it can be local to a function too, or a statement block. The idea is: anywhere where you may have a variable, you may also have a property, with the same applicability of the variable. In the case you choose for a property, the property have access to the same scope where it is enclose (the private members of the class or struct where it was declared, or the local scope of the function, etc.).
 3. Properties are translated on basis on what operations would have been
 done on it if it were a variable, and not a fancy representation of a
 function call. This should allow  property++  and  property += 5  (given
 that it provides both a getter and at least a setter).

But ++, -- and op= have their own definitions with certain class-types that can't be defined in terms of only setter and getter functions.

For composite types, you implement properties with a validator and a refresher, along with the setter and the getter. The validator is called before changing the object, with a copy of the object with its new instance as a parameter. It either returns or throw an exception. The refresher is called after changing the object, to do whatever would have been done if the setter was called to change the object. A property += 5 translates more or less like this: { auto tmp = property.value.dup; tmp.opAddAssign(5); property.validate(tmp); // may throw property.refresh(); } Of course, the compiler is responsible to optimize this. If the property doesn't implement a validator, there is no need to dup.
 I don't agree. Properties shouldn't be used as functions at all. They
 should manage writes and reads to a single property.

Me too. What I mean is that, if the programmer wants that simply accessing a symbol without () calls a function, he/she should say it explicitly by making it a read-only property. Just to avoid allowing things like if (fork)... without the original programmer intent.
Feb 23 2007
parent Michiel <nomail please.com> writes:
Miles wrote:

 But ++, -- and op= have their own definitions with certain class-types
 that can't be defined in terms of only setter and getter functions.

For composite types, you implement properties with a validator and a refresher, along with the setter and the getter. The validator is called before changing the object, with a copy of the object with its new instance as a parameter. It either returns or throw an exception. The refresher is called after changing the object, to do whatever would have been done if the setter was called to change the object. A property += 5 translates more or less like this: { auto tmp = property.value.dup; tmp.opAddAssign(5); property.validate(tmp); // may throw property.refresh(); } Of course, the compiler is responsible to optimize this. If the property doesn't implement a validator, there is no need to dup.

That's a good idea. Better than declaring each operator again. Though less efficient, I suppose, if you do want to validate. -- Michiel
Feb 24 2007
prev sibling next sibling parent Serg Kovrov <kovrov no.spam> writes:
Jarrett Billingsley wrote:
 True properties would be understood by the compiler as a distinct construct, 
 rather than a hackish rewrite of assignment into a call.  This would allow, 
 among other things, for templated properties; properties as the destination 
 of op=, ++, and --; and the abolishment of the '&' when getting the address 
 of a function or delegate.  As well as preventing such foolishness as 
 "writefln = 6;". 

Yes, exactly. -- serg.
Feb 21 2007
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Jarrett Billingsley wrote

 What are 'real properties'?

True properties would be understood by the compiler as a distinct construct, rather than a hackish rewrite of assignment into a call.

But what are the benefits of "distinct constructs" in terms of provable correctness? Btw. using the assignment symbol as an alternative for a call seems very canonical to me.
 This would allow, among other things, for templated
 properties;

What are "templated properties"? Are you really declaring, that a "real" property is a "tempülated" property?
 properties as the destination of op=, ++, and --;

That is already possible, except you do not want to buy such.
 the abolishment of the '&' when getting the address of a function
 or delegate.

I don't understand that. Would you please elaborate on that? -manfred
Feb 22 2007
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Manfred Nowak wrote:
 Jarrett Billingsley wrote
 
 What are 'real properties'?

construct, rather than a hackish rewrite of assignment into a call.

But what are the benefits of "distinct constructs" in terms of provable correctness? Btw. using the assignment symbol as an alternative for a call seems very canonical to me.

Yes, it's quite normal for an assignment to a property to actually be a function call. It's *not* normal for an assignment to a _function_ to call said function... Some functions simply weren't meant to be properties. [snip]
 the abolishment of the '&' when getting the address of a function
 or delegate.

I don't understand that. Would you please elaborate on that?

--- import std.stdio; int foo() { writefln("foo() called"); return 0; } void main() { auto x = foo; writefln("x: ", typeid(typeof(x))); auto y = &foo; writefln("y: ", typeid(typeof(y))); } --- Output: --- foo() called x: int y: int()* --- So currently the line declaring & initializing x calls 'foo' and uses the return type as value, instead of x becoming a function pointer and assigning a pointer to 'foo' as its value. To get the function pointer you need to add an '&', like with y. If 'foo' was not implicitly a property, the language could be changed so that the extra '&' would no longer be necessary. There would only be one possible value for 'foo' to evaluate to: a pointer to the function.
Feb 22 2007
parent Manfred Nowak <svv1999 hotmail.com> writes:
Frits van Bommel wrote

 It's *not* normal for an assignment to a _function_ to call said
 function... 
 Some functions simply weren't meant to be properties.

assignment be interpreted as a call. Seen this way property is just a synonym for function---and the last sentence of the citation above becomes senseless.
 So currently the line declaring & initializing x calls 'foo' and
 uses the return type as value

properties, as presented, is of any usefulness. If a set-property can be seen as an agent bound to a deposit box for input, then a get-property should return an agent capable of answering questions about the output, i.e. a delegate. Do you see the consequences? The confusion you presented stems from not distinguishing between the type of the return value "typeof" and the type of the return agent "agentof": typeid( typeof( foo)) == "int" typeid( agentof( foo)) == "int()" So "&foo" is undefined in the sense that it can approximately mean both: "&typeof( foo)" and "&agentof( foo)". -manfred
Feb 22 2007
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message 
news:erkjin$2t1o$1 digitalmars.com...
 Jarrett Billingsley wrote

 What are "templated properties"? Are you really declaring, that a
 "real" property is a "tempülated" property?

No, I mean with the current "properties" it's not possible to use template functions as properties, i.e. class A { void x(T)(T value) { writefln("I'm a property and I got: ", value); } } void main() { A a = new A(); a.x = 5; // error, a.x is not an lvalue } This is because a.x is actually a template with one function declared in it. When you try to assign to it, it makes no sense, since a.x is a template. That check happens _before_ the rewrite to a function call happens. If, however, you had a separate property syntax: class A { property x { void opSet(T)(T value) // just guessing at the name { writefln("I'm a property and I got: ", value); } } } void main() { A a = new A(); a.x = 5; // works } D would find that a.x is a property. Assignment to a property is unambiguously a call to its opSet function, and so the call would be rewritten as a.x.opSet(5); which can then cause the template to be instantiated properly. I suppose this could also be done with the current "properties" :) (and hopefully it will, because I know that there is no way in hell that any property syntax is ever going to make it into D)
 That is already possible, except you do not want to buy such.

Uhh... "buy"? I don't know what you're trying to say, and I don't know how this is at all possible (unless you mean that "trick" that you posted involving using an extra dummy index).
Feb 22 2007
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Jarrett Billingsley wrote

 No, I mean with the current "properties" it's not possible to use
 template functions as properties

I do not see the general usability if such would be enabled. Under which circumstances are untemplated classes useful, that contain templated functions?
 Uhh... "buy"?  I don't know what you're trying to say, and I don't
 know how this is at all possible (unless you mean that "trick"
 that you posted involving using an extra dummy index). 

"Buy" means, that it is somehow costly. For a class C one has to define an inner class I that implements the required op=, ++, and -- operators; has to declare within Class C the property as approximately "I property;"; has to extend the constructor of Class C by a "property= new I;". Then one can code: auto c= new C; c.property <op>= ... The specs | Note: Properties currently cannot be the lvalue of an op=, ++, or | -- operator. do not hold for class properties. -manfred
Feb 23 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message 
news:erns67$2d2$1 digitalmars.com...
 I do not see the general usability if such would be enabled. Under
 which circumstances are untemplated classes useful, that contain
 templated functions?

I've found templated member functions immensely useful for doing things with variant-like types, though I encounter that a lot only because I'm writing a dynamically-typed scripting language. Additionally, I use tuples for variadic functions because there are some things which would just be too ugly/slow with normal variadic functions. I have a ".call" method in my interpreter class that I can just pass a tuple of arguments, and it'll automatically convert them to variant types and push them onto the interpreter stack, and it does that in about six lines of code. Other uses would include maybe an IO class that has to be able to write or read any kind of data. Much easier to do so with a templated member function than with a million overloads (I'm looking at _you_, std.stream).
 For a class C one has to define an inner class I that implements the
 required op=, ++, and -- operators; has to declare within Class C
 the property as approximately "I property;"; has to extend the
 constructor of Class C by a "property= new I;".

 Then one can code:
  auto c= new C;
  c.property <op>= ...

Oh, I see. Yeah, that is possible. You could even do it with an inner struct, too. Would be lighter weight.
 The specs
 | Note: Properties currently cannot be the lvalue of an op=, ++, or
 | -- operator.
 do not hold for class properties.

It holds for _typical_ class properties, i.e. implicit function calls. But you're right, they can be made to _look_ like they're working correctly with a workaround.
Feb 23 2007