January 30, 2013
On Wednesday, 30 January 2013 at 19:26:01 UTC, Timon Gehr wrote:
> So I do not see what could be considered weird.

Right, I just don't know much about aliases.
January 30, 2013
On Wednesday, 30 January 2013 at 18:05:08 UTC, Zach the Mystic wrote:
> [..]

How about using this new namespace_thingy keyword:

struct S
{
    private int value;

    namespace_thingy prop
    {
        int get() { return value; }
        prop opAssign(int v) { value = v; return prop; }

        // int data; // error: can't have data here
    }
}

The compiler would implicitly create something like:

struct S
{
    private int value;

    int prop_get() { return value; }
    int prop_opAssign(int v) { value = v; return prop_get(); }
}

...

S s;
int v1 = s.prop;        // lowered to s.prop_get()
int v2 = (s.prop = v1); // lowered to s.prop_opAssign(v1)
assert(v1 == v2);
January 30, 2013
On Wednesday, 30 January 2013 at 18:36:17 UTC, Dmitry Olshansky wrote:
> I have one key problem - the hidden pointer detail.
> In other words how should it find the instance of the outer struct to to access it?
>
> struct A{
> 	int a;
> 	struct B{
> 		void foo(){ a = 42; }
> 	}	
> 	B b;
> }
>
> A a;
> a.b.foo(); //how that b is supposed to know it's outer struct without the hidden pointer?
>
> auto x = a.b;
> x.foo();// and now what?

It seems struct B does need a pointer... and yet it only needs it in compile time. "auto x = a.b" is no different from "alias a.b x", because when you have no data, you have no data to worry about! a.b is nothing but a namespace with full struct semantics.

I can only say that my intuition tells me that this is easily managed. I cannot tell you what adjustments need to be made to the compiler to get this to come out right.

But what if B actually had some data? The only solution is to have one pointer for every struct it's nested inside of. I can imagine it getting tricky in this case. If it were so tricky as to be prohibitive to implement, then all is not lost. You can still implement zero-data structs as properties. In that case, I suggest weaving the implementation in directly with the Highlanders, because Highlanders will be much less appealing for any other use.
January 30, 2013
On Wednesday, 30 January 2013 at 19:44:43 UTC, TommiT wrote:
> On Wednesday, 30 January 2013 at 18:05:08 UTC, Zach the Mystic wrote:
>> [..]
>
> How about using this new namespace_thingy keyword:
>
> struct S
> {
>     private int value;
>
>     namespace_thingy prop
>     {
>         int get() { return value; }
>         prop opAssign(int v) { value = v; return prop; }
>
>         // int data; // error: can't have data here
>     }
> }
>
> The compiler would implicitly create something like:
>
> struct S
> {
>     private int value;
>
>     int prop_get() { return value; }
>     int prop_opAssign(int v) { value = v; return prop_get(); }
> }
>
> ...
>
> S s;
> int v1 = s.prop;        // lowered to s.prop_get()
> int v2 = (s.prop = v1); // lowered to s.prop_opAssign(v1)
> assert(v1 == v2);

I think you're thinking along the right lines, but this is no better than what's already been suggested. From everything I've read, reusing old keywords to do new things in new places is a time-honored D tradition, and adding new ones is very much frowned upon.

Also, because the "namespace_thingy"s have so much in common with structs, I think it would be misleading to call them something else. The lowering you're talking about already happens, in its own way, with the operator overloads. In fact, these overloads were designed *specifically* to allow struct and class instances to meld in seamlessly with built-in types.

Just look at Walter's recent article for half floats. The whole article demonstrates D's ability to do exactly what everybody is trying to get their properties to do. Now we just have to get rid of the performance overhead by treating structs with no data as namespaces instead of the more commonly held perception that they are only supposed to work on their own data! Hurrah!
January 30, 2013
On Wednesday, 30 January 2013 at 21:41:58 UTC, Zach the Mystic wrote:
> But what if B actually had some data? The only solution is to have one pointer for every struct it's nested inside of. I can imagine it getting tricky in this case. If it were so tricky as to be prohibitive to implement, then all is not lost. You can still implement zero-data structs as properties. In that case, I suggest weaving the implementation in directly with the Highlanders, because Highlanders will be much less appealing for any other use.

I should correct myself, I think. You need one pointer for every struct nested which actually holds data.

And I take back the connection between Highlanders and zero-data structs. The other possible use for Highlanders which I was thinking of is for quick prototyping, since "foo struct {}" is much easier to type than "struct Foo {}; Foo foo;". I see no real problem with these even if non-static, non-zero-data nested structs are not allowed access to their parent structs.
January 30, 2013
On Wednesday, 30 January 2013 at 21:58:53 UTC, Zach the Mystic wrote:
> Also, because the "namespace_thingy"s have so much in common with structs, I think it would be misleading to call them something else.

The problem of using empty struct variables is that they take up memory. They have to, because you can make a pointer to a variable and then you can dereference that variable. There has to be at least a byte of memory to dereference.

So, really, the only zero-overhead way to do this is to introduce a new keyword that creates something that you can't take the address of, because it kind of doesn't exist (like a namespace). It exists only in the sense that it can be used to tell the compiler which operators and functions to call. That's what my namespace_thingy is.
January 30, 2013
On 01/30/2013 11:30 PM, TommiT wrote:
> On Wednesday, 30 January 2013 at 21:58:53 UTC, Zach the Mystic wrote:
>> Also, because the "namespace_thingy"s have so much in common with
>> structs, I think it would be misleading to call them something else.
>
> The problem of using empty struct variables is that they take up memory.
> They have to, because you can make a pointer to a variable and then you
> can dereference that variable. There has to be at least a byte of memory
> to dereference.
>

No, that is not why. The only conceivable reason empty structs take up space is so that different instances have different addresses.

> So, really, the only zero-overhead way to do this is to introduce a new
> keyword that creates something that you can't take the address of,
> because it kind of doesn't exist (like a namespace). It exists only in
> the sense that it can be used to tell the compiler which operators and
> functions to call. That's what my namespace_thingy is.

January 30, 2013
On Wednesday, 30 January 2013 at 22:41:23 UTC, Timon Gehr wrote:
>> The problem of using empty struct variables is that they take up memory.
>> They have to, because you can make a pointer to a variable and then you
>> can dereference that variable. There has to be at least a byte of memory
>> to dereference.
>>
>
> No, that is not why. The only conceivable reason empty structs take up space is so that different instances have different addresses.

Oh, thanks for clearing that up.

January 30, 2013
On Wednesday, 30 January 2013 at 19:44:43 UTC, TommiT wrote:
> [..]

More of fleshing out of namespace_thingy:

struct S
{
private:
    int m_startTime;
    int m_endTime;
    int m_duration;

public:
    namespace_thingy start
    {
        int opGet() const { return m_startTime; }

        start opAssign(int t)
        {
            m_startTime = t;
            m_duration = m_endTime - m_startTime;
            return start;
        }
    }

    namespace_thingy end
    {
        int opGet() const { return m_endTime; }

        end opAssign(int t)
        {
            m_endTime = t;
            m_duration = m_endTime - m_startTime;
            return end;
        }

        dur opAssign(string s : "+")(int t)
        {
            m_endTime += t;
            m_duration = m_endTime - m_startTime;
            return dur;
        }
    }

    namespace_thingy dur
    {
        dur opAssign(int t)
        {
            m_duration = t;
            m_endTime = m_startTime + m_duration;
            return dur;
        }

        bool opEquals(int t) const
        {
            return m_duration == t;
        }
    }

    this(int t)
    {
        start = 0;
        end = t;
        assert(dur == 100);
    }
}

...

S s;
s.start = 1;
s.end = 8;
assert(s.dur == 7);
s.end += 3;
assert(s.dur == 10);

int v = s.start;

s.start += 42; // error: no match for opAssign!"+"(S.start, int)
               //                 nor opAssign!"+"(int, int)
int d = s.dur; // error: no conversion from S.dur to int
January 31, 2013
On Wednesday, 30 January 2013 at 22:30:10 UTC, TommiT wrote:
> On Wednesday, 30 January 2013 at 21:58:53 UTC, Zach the Mystic wrote:
>> Also, because the "namespace_thingy"s have so much in common with structs, I think it would be misleading to call them something else.
>
> The problem of using empty struct variables is that they take up memory. They have to, because you can make a pointer to a variable and then you can dereference that variable. There has to be at least a byte of memory to dereference.
>
> So, really, the only zero-overhead way to do this is to introduce a new keyword that creates something that you can't take the address of, because it kind of doesn't exist (like a namespace). It exists only in the sense that it can be used to tell the compiler which operators and functions to call. That's what my namespace_thingy is.

I disagree. The compiler can easily tell if a struct is defined with no data, and simply optimize away the pointer in the process.