www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Inner classes - More expressiveness needed

reply "Janice Caron" <caron800 googlemail.com> writes:
I can't call this a bug, because I think it's behaving as documented.
Nonetheless, it seems to be that D could be more expressive. The
following won't compile:

    class Outer
    {
        int n;

        class Inner
        {
            static int f() { return n; }
        }
    }

The error is:
Error: need 'this' to access member n

The problem is that the word "static" is horribly overused, and
doubles up to mean BOTH "the function does not have a this pointer"
AND "this function does not have an outer pointer".

There seems no way to express "please can my function have an outer
pointer but not a this pointer" (which is what I was trying to
achieve).

There also seems no way to express "please can my function have a this
pointer but not an outer pointer". (I wasn't trying to achieve that,
but it could conceivably be useful).

I wonder if we might find some way of expressing those ideas?
Oct 25 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Janice Caron" <caron800 googlemail.com> wrote in message 
news:mailman.508.1193317715.16939.digitalmars-d puremagic.com...
I can't call this a bug, because I think it's behaving as documented.
 Nonetheless, it seems to be that D could be more expressive. The
 following won't compile:

    class Outer
    {
        int n;

        class Inner
        {
            static int f() { return n; }
        }
    }

 The error is:
 Error: need 'this' to access member n

 The problem is that the word "static" is horribly overused, and
 doubles up to mean BOTH "the function does not have a this pointer"
 AND "this function does not have an outer pointer".

 There seems no way to express "please can my function have an outer
 pointer but not a this pointer" (which is what I was trying to
 achieve).

 There also seems no way to express "please can my function have a this
 pointer but not an outer pointer". (I wasn't trying to achieve that,
 but it could conceivably be useful).

 I wonder if we might find some way of expressing those ideas?
I have no idea how that'd be implemented. The thing is that the 'outer' is not contained somewhere special; it's just a hidden member of every instance of the inner class. When you access outer members, you're really doing this.outer.member. For a static inner function, however, there's no way to associate an "instance of the function" (which doesn't really mean much) with an instance of Outer. Furthermore there are (please don't hit me) static inner classes, which do not have an outer pointer. Again, the outer pointer is per-instance, so this just involves not putting an outer pointer in the instance.
Oct 25 2007
prev sibling next sibling parent reply Gregor Richards <Richards codu.org> writes:
I hate when people say that "static" is overused, when they really just 
don't know what static means.

There are only two meanings for "static" in D:

  * Static conditionals.
  * Static declarations.

For static declarations, the meaning of static is 100% consistent. It 
means that the given declaration, though accessed by its semantic scope, 
exists in the global context. Implementation-wise, this means that it 
has no context pointer whatsoever. This is far more consistent than C, 
C++, Java, ...

  - Gregor Richards
Oct 25 2007
next sibling parent reply Matti Niemenmaa <see_signature for.real.address> writes:
Gregor Richards wrote:
 I hate when people say that "static" is overused, when they really just
 don't know what static means.
 
 There are only two meanings for "static" in D:
 
  * Static conditionals.
  * Static declarations.
 
 For static declarations, the meaning of static is 100% consistent. It
 means that the given declaration, though accessed by its semantic scope,
 exists in the global context. Implementation-wise, this means that it
 has no context pointer whatsoever. This is far more consistent than C,
 C++, Java, ...
Even if you count "static assert" as a conditional, there's still "static import", which is already three completely distinct uses for one keyword. The only other keyword with that many is "in". (One of which you might not even count, as it's obvious to anybody without programming experience what "a in b" means. With "static", none of the meanings are as obvious.) As far as I can come up with, "out", "scope", and "void" have two distinct meanings, and the rest have one. So, despite knowing what "static" means, I'd say it's the most used keyword in the language, and overused. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Oct 25 2007
parent reply Henning Hasemann <hhasemann web.de> writes:
 Even if you count "static assert" as a conditional, there's still
 "static import", which is already three completely distinct uses for
 one keyword. The only other keyword with that many is "in". (One of
 which you might not even count, as it's obvious to anybody without
 programming experience what "a in b" means. With "static", none of
 the meanings are as obvious.)
 
 As far as I can come up with, "out", "scope", and "void" have two
 distinct meanings, and the rest have one.
'import' has 2: 'import foo', 'import("foo")' 'mixin' has at least 2: 'mixin Foo!()', 'mixin("foo")' 'this' has at least 2: 'this() { }', 'this.foo' 'alias' has at least 2: 'alias myint int;', 'tempalte Templ(alias T){}' I'd guess one could find more examples (const in D2?). I dislike this too. I dont think its such a big problem to have more keywords, especially when they denote different features. But it seems to me Walter & co are more concerned about polluting the code namespace then by this problem. (Which has it good sides too when it comes to backwards compatibility, but I feel it should be more important to choose expressive keywords then retaining backwards compatibility especially in the 2.x branch I think it would be a good idea to reconsider keyword choices as backwards compatibility is not an issue there.) Henning -- GPG Public Key: http://gpg-keyserver.de/pks/lookup?op=get&search=0xDDD6D36D41911851
Oct 25 2007
parent Matti Niemenmaa <see_signature for.real.address> writes:
Henning Hasemann wrote:
 As far as I can come up with, "out", "scope", and "void" have two
 distinct meanings, and the rest have one.
'import' has 2: 'import foo', 'import("foo")' 'mixin' has at least 2: 'mixin Foo!()', 'mixin("foo")' 'this' has at least 2: 'this() { }', 'this.foo' 'alias' has at least 2: 'alias myint int;', 'tempalte Templ(alias T){}'
Gregor grouped static's 7 meanings into 2. I did the same with 'import' and 'mixin' in the above. I'd say you're right about 'this' at least, and I never understood template alias parameters so you're probably right about that one, too. :-)
 (Which has it good sides too when it comes to backwards compatibility,
 but I feel it should be more important to choose expressive keywords
 then retaining backwards compatibility especially in the 2.x branch I
 think it would be a good idea to reconsider keyword choices as
 backwards compatibility is not an issue there.)
Agreed. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Oct 25 2007
prev sibling parent Derek Parnell <derek psych.ward> writes:
On Thu, 25 Oct 2007 08:09:34 -0700, Gregor Richards wrote:

 I hate when people say that "static" is overused, when they really just 
 don't know what static means.
 
 There are only two meanings for "static" in D:
 
   * Static conditionals.
   * Static declarations.
 
 For static declarations, the meaning of static is 100% consistent. It 
 means that the given declaration, though accessed by its semantic scope, 
 exists in the global context. Implementation-wise, this means that it 
 has no context pointer whatsoever. This is far more consistent than C, 
 C++, Java, ...
 
   - Gregor Richards
How does the module constructor fit into this classification? module xyz; static this() { . . . } -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Oct 25 2007
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
I can't call this a bug, because I think it's behaving as documented.
 Nonetheless, it seems to be that D could be more expressive. The
 following won't compile:

    class Outer
    {
        int n;

        class Inner
        {
            static int f() { return n; }
        }
    }

 The error is:
 Error: need 'this' to access member n

 The problem is that the word "static" is horribly overused, and
 doubles up to mean BOTH "the function does not have a this pointer"
 AND "this function does not have an outer pointer".

 There seems no way to express "please can my function have an outer
 pointer but not a this pointer" (which is what I was trying to
 achieve).
And what would you have the outer member point to? :) It needs to point to an instance of the outer class, and if you have a static function, there is no instance of an inner or outer class. If you need a function that requires an instance of the outer class, but not an instance of the inner class, the function belongs in the outer class. I think that is what you wanted?
 There also seems no way to express "please can my function have a this
 pointer but not an outer pointer". (I wasn't trying to achieve that,
 but it could conceivably be useful).
This is done by creating another class in the same module. -Steve
Oct 25 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 And what would you have the outer member point to? :)  It needs to point to
 an instance of the outer class, and if you have a static function, there is
 no instance of an inner or outer class.

 If you need a function that requires an instance of the outer class, but not
 an instance of the inner class, the function belongs in the outer class.  I
 think that is what you wanted?
Hmm... How to explain...? OK, to start with, I had a class which looked something like this: class B { int n; private this(int n) { this.n = n; } static B opCall(int n) { return new B(n); } int f() { return 0; } } B B_Factory(int n) { return new B(n); } // In another file auto b = B(42); int n = b.f; This all worked very nicely. But then I decided to make B an inner class, so naturally I tried just wrapping it in class A {}, to give class A { int m; class B { int n; private this(int n) { this.n = n; } static B opCall(int n) { return new B(n); } int f() { return m; } } B B_Factory(int n) { return new B(n); } } // In another file auto a = new A; auto b = a.B(42); int n = b.f; and this is the point at which it stopped compiling. I guess maybe it was a dumb thing to do, using static opCall and making the constructor private. The thing is, while the static opCall does not compile, the standalone function B_factory() is perfectly OK and compiles just fine. That's because B_Factory is considered to be a member function of A, wheras A.B.opCall() isn't. So, when you said "If you need a function that requires an instance of the outer class, but not an instance of the inner class, the function belongs in the outer class", you were spot on! I can't argue with that. It just came as a bit of a surprise that wrapping a bunch of classes inside class A() caused some static functions to stop working.
Oct 25 2007
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Janice Caron" wrote
 On 10/25/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:
 And what would you have the outer member point to? :)  It needs to point 
 to
 an instance of the outer class, and if you have a static function, there 
 is
 no instance of an inner or outer class.

 If you need a function that requires an instance of the outer class, but 
 not
 an instance of the inner class, the function belongs in the outer class. 
 I
 think that is what you wanted?
Hmm... How to explain...? OK, to start with, I had a class which looked something like this: class B { int n; private this(int n) { this.n = n; } static B opCall(int n) { return new B(n); } int f() { return 0; } } B B_Factory(int n) { return new B(n); } // In another file auto b = B(42); int n = b.f; This all worked very nicely. But then I decided to make B an inner class, so naturally I tried just wrapping it in class A {}, to give class A { int m; class B { int n; private this(int n) { this.n = n; } static B opCall(int n) { return new B(n); } int f() { return m; } } B B_Factory(int n) { return new B(n); } } // In another file auto a = new A; auto b = a.B(42); int n = b.f; and this is the point at which it stopped compiling. I guess maybe it was a dumb thing to do, using static opCall and making the constructor private. The thing is, while the static opCall does not compile, the standalone function B_factory() is perfectly OK and compiles just fine. That's because B_Factory is considered to be a member function of A, wheras A.B.opCall() isn't.
Yeah, I see your point. I don't think there's a way to name the function a.B() without having a static opCall, which isn't what you want. So I guess B_Factory will have to do :) -Steve
Oct 25 2007
prev sibling parent Nathan Reed <nathaniel.reed gmail.com> writes:
Janice Caron wrote:
 I can't call this a bug, because I think it's behaving as documented.
 Nonetheless, it seems to be that D could be more expressive. The
 following won't compile:
 
     class Outer
     {
         int n;
 
         class Inner
         {
             static int f() { return n; }
         }
     }
 
 The error is:
 Error: need 'this' to access member n
 
 The problem is that the word "static" is horribly overused, and
 doubles up to mean BOTH "the function does not have a this pointer"
 AND "this function does not have an outer pointer".
 
 There seems no way to express "please can my function have an outer
 pointer but not a this pointer" (which is what I was trying to
 achieve).
 
 There also seems no way to express "please can my function have a this
 pointer but not an outer pointer". (I wasn't trying to achieve that,
 but it could conceivably be useful).
 
 I wonder if we might find some way of expressing those ideas?
Isn't what you want just a member function of Outer? If you need to get at it through an object of type Inner, you could simply use a forwarding function, e.g.: class Outer { int n; int f() { return n; } class Inner { int f() { return outer.f(); } } } Thanks, Nathan Reed
Oct 25 2007