On Fri, 01 Feb 2013 01:52:29 -0500, Zach the Mystic
<[email protected]> wrote:
On Friday, 1 February 2013 at 04:33:05 UTC, Steven Schveighoffer wrote:
No, the struct must have data. If it doesn't, how does it get back to
the owner type? In other words, your n struct must have a pointer to
the myStruct instance it intends to modify _n on.
How does any function get hooked up with data? The compiler figures out
what data is to be passed to which function. It's no different from how
the compiler figures out how to pass data defined in one module to
functions defined in a different module. Empty structs are just
namespaces with powerful semantics. They have no pointers, unless
they're nested in a struct with data, in which case they have the same
pointer as any member function of that struct.
struct A
{
int q = 23;
void incrementQ() { ++q; }
}
How on earth could this function increment q when it's not even defined
in the function?!?!? It must be a miracle. Oh, no wait, it needs a
pointer to the struct in question. Duh.
No need to get snippy :) Especially when you are wrong.
Try this:
struct A
{
int q;
struct B
{
void foo() {q++;}
}
}
Won't compile. That's becuase foo is passed a reference to the A.B
struct, not the A struct.
If you want it to compile, B will *necessarily* have to have a pointer to
A.
If you want B's methods to be passed A's pointer, then this is not a
struct. Plain and simple. It's just a namespace, the "just like any
other struct" is meaningless, since it isn't.
Now, try this:
struct S {}
pragma(msg, sizeof(S).stringof); // outputs 1 (empty structs must have
some size).
void foo()
{
int q;
struct A
{
void foo() {q++;}
}
pragma(msg, sizeof(A).stringof); // outputs 4 (or 8 on 64-bit machines)
}
Why? Because the reason those "miracle" nested structs work is because
they have a hidden context pointer.
Even empty structs have size of 1 byte because they must have a 'this'
pointer.
There's no difference with data-less structs inside regular structs.
struct A
{
int q;
incrementQ struct
{
void opCall() { ++q; }
}
}
Where's the need for some hocus-pocus mystery pointer here? The empty
struct has no data to worry about. Functions inside the empty struct get
the same damn pointer as the other functions in struct A.
Then this is not a normal struct, in fact it has nothing to do with a
struct.
But of course, you can't do this:
struct B
{
int _q;
q struct
{
int opUnary(string s)() if (s == "++")
{
writeln("You know, I just wanted to have a conversation while I
was busy incrementing q");
++_q;
writeln("I did all sorts of stuff with the increment operator
while I was at it");
return _q;
}
}
}
...with normal function calls.
Certainly you can:
struct B
{
int _q;
@property auto q()
{
static struct incrementer
{
int *_q;
int opUnary(string s)() if (s == "++")
{
writeln("You know, I just wanted to have a conversation while I
was busy incrementing q");
++(*_q);
writeln("I did all sorts of stuff with the increment operator
while I was at it");
return *_q;
}
}
return incrementer(&_q);
}
}
Although, because of dumb rvalue/lvalue rules (apparently, incrementer is
not an lvalue, so can't have ++ called on it), this doesn't actually
compile...
Through some finagling, I can get this to compile, but it's not usable
with this compiler bug:
import std.stdio;
struct B
{
int _q;
struct incrementer
{
int *_q;
int opUnary(string s)() if (s == "++")
{
writeln("You know, I just wanted to have a conversation while
I was busy incrementing q");
++(*_q);
writeln("I did all sorts of stuff with the increment operator
while I was at it");
return *_q;
}
}
private incrementer qinc; // needed to make incrementer an lvalue.
@property ref incrementer q()
{
qinc._q = &_q;
return qinc;
}
}
void main()
{
B b;
assert(b._q == 0);
++b.q; // b.q++ doesn't work, another bug
assert(b._q == 1);
}
But I think actually, if we are going to define get and set in C# style,
it would be useful to be able to define all the operators. So that part
of the plan has merit.
I think you need to drop the struct moniker. This is not a struct. You
do that, and I think your proposal is on more solid ground.
Unless, of course, you pass the pointer to myStruct as the 'this'
reference.
Ain't no "this" in an empty struct. Use "outer.this" instead.
outer is the pointer I am referring to. It's not magic, it must come from
somewhere. If the struct has no this pointer, it's not a struct. A
data-less struct *STILL* has a this pointer.
But then, this isn't a normal struct, and
I'm really failing to see why we have to make this a struct at all.
Because it's already implemented, except for a few details, because it
opens up possibilities for properties other languages could only dream
of, and because it obviates the need for tags like @property to provide
far weaker functionality.
Hand waving doesn't solve the problems. The details are important to
resolve.
What it seems like you have done is hijacked the 'struct' keyword for a
property. It isn't a struct, and it doesn't obviate the need for a tag.
You say it's complicated, but I ask you this: does any other proposal
completely eliminate the so-called eye-sore "@property" while also
providing functionality with unknown potential which goes far beyond
what people are used to? And the owner pointer problem is only a problem
if we want to make the language complete and consistent with regard to
normal non-static structs holding an outer struct pointer. I think
having a use case for this type of struct would seal the deal, but as it
is, I'm not sure.
What I mean by complicated is that it seems like a lot more work than it
should be.
If we want to define new syntax to define properties, let's do it in a way
that is concise and to the point. I don't want to make properties look
like structs, they are not structs.
-Steve