On Thursday, 31 January 2013 at 22:54:21 UTC, Steven Schveighoffer wrote:
C# has properties like this:

property int foo {
  get {return _foo;}
  set {_foo = value;}
}

Your proposal looks like this:

foo struct {
   int opGet() {return _foo;}
   void opSet(int value) {_foo = value;}
}

What I see is that the getter and setter are assigned specific contextual keywords (opGet vs. get, and opSet vs. set). It seems like a very similar (albeit more verbose) solution.

What I had originally suggested for properties is this:

property int foo {
   int get() {return _foo;} // only one getter allowed
   void set(int v) {_foo = v;}
void set(float v) {_foo = (int)v;} // more than one setter allowed
}

I think these are all along the same line of solutions. I don't think they are bad, but clearly they weren't used 4 years ago, so it may be difficult to convince Walter to use them now.

My opGet is just another opXXX definable for all structs, not just properties.

I didn't see that, but I also don't really see the point of that. What value does opGet have unless it's a getter for a property?

I had said it was necessary to achieve structs as properties, but I think I was wrong. It's just the equivalent of:

int __someRandomFunction() { return _propValue; }
alias __someRandomFunction this;

But it would be syntactically nicer, much like Highlander structs are syntactically nicer. Therefore, the only language change absolutely required would be making non-static structs nested in structs behave like non-static structs nested in functions, which they arguably should do anyway. Also under the hood, some important optimizations getting rid of pointers for data-less structs.

This is a VERY bad idea. A struct is POD. For example, consider a range type for a container. You may not NEED to have a pointer to the container, so that is wasted bytes.

Also note that structs are not meant to have internal pointers.
 So a "property" struct with an internal pointer

The strange case for a struct type inside a function kind of makes sense, because of the ability to access the function's variables, and because you can't really move the stack frame.

-Steve

I think my suggestion goes far beyond what you suspect. It goes way beyond mere getting and setting of variables. Here is basically how you implement a basic int as a property, assuming my new syntax and language adjustments. You need: 1) a struct to have the property in, which is just a normal struct. 2) An actual integer which will be indirectly accessed by using the properties. Let's call it "_n" and the property "n". 3) a struct to hold all of the property functions which access _n. THIS STRUCT CONTAINS NO DATA OF ITS OWN. 4) A bunch of methods implementing all the operators you want. For int, that's quite a lot, so I'll shorten it to a getter, a setter, and an adder. I'll even leave out opGet and use an alias to what might as well be opGet. I'll give the adder a little personality because what's the point of properties if they don't do something different from a basic type?

struct myStruct
{
  int _n;
  n struct
  {
    int __mightAsWellBeOpGet() { return _n; }
    alias __mightAsWellBeOpGet this;

    int opAssign(int newN) { _n = newN; return _n; }
    int opBinary(string op) (int rhs)
    {
      static if (op == "+")
      {
        writeln("You sure are adding a funky int, my friend...");
        return _n + rhs;
      }
      else static assert(0, "Operator "~op~" not implemented");
    }
  }
}

This is not some kind of special property implementation. n is a struct. It has no data and therefore is a very peculiar kind of struct. A struct with no data needs only one instance, ever. Copying it is pointless. Taking its address is pointless. Creating a new instance is pointless. Passing it by ref is pointless. All operations which require more than one instance are pointless, which is why it doesn't need a separately defined type. The type and the instance can therefore use the same name, n in this case.

Note that n uses the new rule which allows it access to its parent's scope, the same way it would in a nested function. The only pointer it needs is the same pointer used for myStruct, since myStruct actually stores some data.

Using the int is as simple as:
myStruct foo;
foo.n = 4; // Calls opAssign
writeln(foo.n); // uses alias this to call __mightAsWellBeOpGet
writeln(foo.n + 4); // Calls opBinary. Prints:

You sure are adding a funky int, my friend...
8

There's literally nothing these properties can't do that a full-fledged struct type couldn't do.

Reply via email to