February 27, 2016
Ok, maybe not but this is what I mean:

Why can't we pass member as as sort of "objects" in there own right to be used for accessing objects?

e.g.,

class A
{
   int? foo;
   A Parent;

   T GetAncestorValue(member<T> field) // member is a new keyword
   {
       var p = this;
       while (!p && !p.field.HasValue)
       {
           p = p.Parent;
       }
       return p.field.Value;
   }
}

(This is pseudo D/C# code)


Then

auto x = a.GetAncestorValue(A:foo) would the properly initialized x.

The code is simple, logical, and makes sense(since foo is just an "offset" and a type. It has type safety and doesn't resort to reflection and passing members as strings, etc. It allows for general access of members rather than having to jump through a bunch of hoops. It should be much faster too.

Is there any fundamental theoretical reason why such a semantic could not be implemented in current object oriented compilers?


February 28, 2016
On Saturday, 27 February 2016 at 18:48:27 UTC, Patience wrote:
> Ok, maybe not but this is what I mean:
>
> Why can't we pass member as as sort of "objects" in there own right to be used for accessing objects?
>
> e.g.,
>
> class A
> {
>    int? foo;
>    A Parent;
>
>    T GetAncestorValue(member<T> field) // member is a new keyword
>    {
>        var p = this;
>        while (!p && !p.field.HasValue)
>        {
>            p = p.Parent;
>        }
>        return p.field.Value;
>    }
> }
>
> (This is pseudo D/C# code)
>
>
> Then
>
> auto x = a.GetAncestorValue(A:foo) would the properly initialized x.
>
> The code is simple, logical, and makes sense(since foo is just an "offset" and a type. It has type safety and doesn't resort to reflection and passing members as strings, etc. It allows for general access of members rather than having to jump through a bunch of hoops. It should be much faster too.
>
> Is there any fundamental theoretical reason why such a semantic could not be implemented in current object oriented compilers?

There is absolutely no technical reason, no. C++ actually has this feature. The reason it has not been implemented in D is it's a (very) rarely used feature in other languages and perfectly possible to implement type-safely and efficiently in a library:

struct nullable(T) {
    T value;
    bool hasValue = false;
}

class A {
   nullable!int foo;
   A parent;

   auto GetAncestorValue(T...)(Member!T field) {
       auto p = this;
       while (p && !field(p).hasValue) {
           p = p.parent;
       }
       return field(p).value;
   }
}

struct Member(T, U) {
    private int fieldId;

    @disable this();

    private this(int id) {
        fieldId = id;
    }

    auto opCall(T that) {
        foreach (i, e; __traits(allMembers, T)) {
            static if (is(typeof(__traits(getMember, that, e)) == U)) {
                if (i == fieldId) {
                    return __traits(getMember, that, e);
                }
            }
        }
        assert(false);
    }
}

template member(alias m) {
    import std.typetuple : TypeTuple;
    alias parentMembers = TypeTuple!(__traits(allMembers, __traits(parent, m)));
    template memberIndex(int n) {
        static if (parentMembers[n] == __traits(identifier, m)) {
            enum memberIndex = n;
        } else {
            enum memberIndex = memberIndex(n+1);
        }
    }
    enum member = Member!(__traits(parent, m), typeof(m))(memberIndex!0);
}

void main() {
    A a = new A();
    A b = new A();
    a.parent = b;
    b.foo.hasValue = true;
    b.foo.value = 3;
    a.foo.value = 15;

    assert(a.GetAncestorValue(member!(A.foo)) == 3);
}

Now, you lose the 'p.field' sugar, and it's possible the built-in feature could drop some safeguards in release mode to make it more efficient, but this should cover most of your concerns.

--
  Simen